Mercurial > octave
view src/mkoctfile.in.cc @ 30564:796f54d4ddbf stable
update Octave Project Developers copyright for the new year
In files that have the "Octave Project Developers" copyright notice,
update for 2021.
In all .txi and .texi files except gpl.txi and gpl.texi in the
doc/liboctave and doc/interpreter directories, change the copyright
to "Octave Project Developers", the same as used for other source
files. Update copyright notices for 2022 (not done since 2019). For
gpl.txi and gpl.texi, change the copyright notice to be "Free Software
Foundation, Inc." and leave the date at 2007 only because this file
only contains the text of the GPL, not anything created by the Octave
Project Developers.
Add Paul Thomas to contributors.in.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 28 Dec 2021 18:22:40 -0500 |
parents | 022747aca7fe |
children | 83f9f8bda883 |
line wrap: on
line source
// %NO_EDIT_WARNING% //////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2022 The Octave Project Developers // // See the file COPYRIGHT.md in the top-level directory of this // distribution or <https://octave.org/copyright/>. // // This file is part of Octave. // // Octave is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Octave is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Octave; see the file COPYING. If not, see // <https://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////// #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include <string> #include <cstring> #include <map> #include <list> #include <algorithm> #include <iostream> #include <fstream> #include <sstream> #include <vector> #include <cstdlib> #if defined (OCTAVE_USE_WINDOWS_API) # include <locale> # include <codecvt> #endif // Programming note: The CROSS macro here refers to building a // cross-compiler aware version of mkoctfile that can be used to cross // compile .oct file for Windows builds of Octave, not that mkoctfile // itself is being cross compiled. // // We don't use the wrapper and gnulib functions when we are building // with CROSS defined. This configuration is only expected to work on // modern systems that should not need to have gnulib to fix POSIX // portability problems. So we just assume a working POSIX system when // CROSS is defined. #if defined (CROSS) # include <stdlib.h> # include <sys/types.h> # include <sys/wait.h> # include <unistd.h> # ifndef OCTAVE_UNUSED # define OCTAVE_UNUSED # endif #else // We are linking against static libs so do not decorate with dllimport. // FIXME: This should be done by the build system. # undef OCTAVE_API # define OCTAVE_API # include "mkostemps-wrapper.h" # include "uniconv-wrappers.h" # include "unistd-wrappers.h" # include "wait-wrappers.h" #endif #if ! defined (OCTAVE_VERSION) # define OCTAVE_VERSION %OCTAVE_CONF_VERSION% #endif #if ! defined (OCTAVE_PREFIX) # define OCTAVE_PREFIX %OCTAVE_CONF_PREFIX% #endif #if ! defined (OCTAVE_EXEC_PREFIX) # define OCTAVE_EXEC_PREFIX %OCTAVE_CONF_EXEC_PREFIX% #endif #include "shared-fcns.h" #if defined (CROSS) static int octave_mkostemps_wrapper (char *tmpl, int suffixlen) { return mkostemps (tmpl, suffixlen, 0); } static int octave_unlink_wrapper (const char *nm) { return unlink (nm); } static bool octave_wifexited_wrapper (int status) { return WIFEXITED (status); } static int octave_wexitstatus_wrapper (int status) { return WEXITSTATUS (status); } #endif static std::string get_line (FILE *fp) { std::ostringstream buf; while (true) { int c = std::fgetc (fp); if (c == '\n' || c == EOF) break; buf << static_cast<char> (c); } return buf.str (); } static std::string get_variable (const char *name, const std::string& defval) { const char *val = getenv (name); if (val && *val) return std::string (val); else return defval; } static std::string quote_path (const std::string& s) { if (s.find (' ') != std::string::npos && s[0] != '"') return '"' + s + '"'; else return s; } static std::string replace_prefix (std::string s) { #if defined (OCTAVE_REPLACE_PREFIX) const std::string match = "${prefix}"; const std::string repl = Voctave_exec_home; std::size_t pos = s.find (match); while (pos != std::string::npos ) { s.replace (pos, match.length (), repl); pos = s.find (match); } #endif return s; } static std::map<std::string, std::string> make_vars_map (bool link_stand_alone, bool verbose, bool debug) { set_octave_home (); std::map<std::string, std::string> vars; vars["OCTAVE_HOME"] = Voctave_home; vars["OCTAVE_EXEC_HOME"] = Voctave_exec_home; vars["API_VERSION"] = %OCTAVE_API_VERSION%; vars["CANONICAL_HOST_TYPE"] = %OCTAVE_CANONICAL_HOST_TYPE%; vars["DEFAULT_PAGER"] = %OCTAVE_DEFAULT_PAGER%; vars["EXEEXT"] = %OCTAVE_EXEEXT%; vars["MAN1EXT"] = %OCTAVE_MAN1EXT%; vars["OCTAVE_VERSION"] = %OCTAVE_VERSION%; vars["ARCHLIBDIR"] = prepend_octave_exec_home (%OCTAVE_ARCHLIBDIR%); vars["BINDIR"] = prepend_octave_exec_home (%OCTAVE_BINDIR%); vars["DATADIR"] = prepend_octave_home (%OCTAVE_DATADIR%); vars["DATAROOTDIR"] = prepend_octave_home (%OCTAVE_DATAROOTDIR%); vars["FCNFILEDIR"] = prepend_octave_home (%OCTAVE_FCNFILEDIR%); vars["IMAGEDIR"] = prepend_octave_home (%OCTAVE_IMAGEDIR%); vars["INFODIR"] = prepend_octave_home (%OCTAVE_INFODIR%); vars["INFOFILE"] = prepend_octave_home (%OCTAVE_INFOFILE%); vars["LIBEXECDIR"] = prepend_octave_exec_home (%OCTAVE_LIBEXECDIR%); vars["LOCALAPIARCHLIBDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALAPIARCHLIBDIR%); vars["LOCALAPIFCNFILEDIR"] = prepend_octave_home (%OCTAVE_LOCALAPIFCNFILEDIR%); vars["LOCALAPIOCTFILEDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALAPIOCTFILEDIR%); vars["LOCALARCHLIBDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALARCHLIBDIR%); vars["LOCALFCNFILEDIR"] = prepend_octave_home (%OCTAVE_LOCALFCNFILEDIR%); vars["LOCALOCTFILEDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALOCTFILEDIR%); vars["LOCALSTARTUPFILEDIR"] = prepend_octave_home (%OCTAVE_LOCALSTARTUPFILEDIR%); vars["LOCALVERARCHLIBDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALVERARCHLIBDIR%); vars["LOCALVERFCNFILEDIR"] = prepend_octave_home (%OCTAVE_LOCALVERFCNFILEDIR%); vars["LOCALVEROCTFILEDIR"] = prepend_octave_exec_home (%OCTAVE_LOCALVEROCTFILEDIR%); vars["MAN1DIR"] = prepend_octave_home (%OCTAVE_MAN1DIR%); vars["MANDIR"] = prepend_octave_home (%OCTAVE_MANDIR%); vars["OCTDATADIR"] = prepend_octave_home (%OCTAVE_OCTDATADIR%); vars["OCTDOCDIR"] = prepend_octave_home (%OCTAVE_OCTDOCDIR%); vars["OCTFILEDIR"] = prepend_octave_exec_home (%OCTAVE_OCTFILEDIR%); vars["OCTFONTSDIR"] = prepend_octave_home (%OCTAVE_OCTFONTSDIR%); vars["STARTUPFILEDIR"] = prepend_octave_home (%OCTAVE_STARTUPFILEDIR%); vars["OCTINCLUDEDIR"] = get_variable ("OCTINCLUDEDIR", prepend_octave_home (%OCTAVE_CONF_OCTINCLUDEDIR%)); vars["INCLUDEDIR"] = get_variable ("INCLUDEDIR", prepend_octave_home (%OCTAVE_CONF_INCLUDEDIR%)); vars["LIBDIR"] = get_variable ("LIBDIR", prepend_octave_exec_home (%OCTAVE_CONF_LIBDIR%)); vars["OCTLIBDIR"] = get_variable ("OCTLIBDIR", prepend_octave_exec_home (%OCTAVE_CONF_OCTLIBDIR%)); std::string DEFAULT_INCFLAGS; #if defined (OCTAVE_USE_WINDOWS_API) DEFAULT_INCFLAGS = "-I" + quote_path (vars["OCTINCLUDEDIR"] + R"(\..)") + " -I" + quote_path (vars["OCTINCLUDEDIR"]); #else DEFAULT_INCFLAGS = "-I" + quote_path (vars["OCTINCLUDEDIR"] + "/..") + " -I" + quote_path (vars["OCTINCLUDEDIR"]); #endif if (vars["INCLUDEDIR"] != "/usr/include") DEFAULT_INCFLAGS += " -I" + quote_path (vars["INCLUDEDIR"]); std::string DEFAULT_LDFLAGS; #if (defined (OCTAVE_USE_WINDOWS_API) || defined (CROSS) || defined (OCTAVE_LINK_ALL_DEPS)) // We'll be linking the files we compile with -loctinterp and -loctave, // so we need to know where to find them. DEFAULT_LDFLAGS += "-L" + quote_path (vars["OCTLIBDIR"]); #endif if (vars["LIBDIR"] != "/usr/lib") DEFAULT_LDFLAGS += " -L" + quote_path (vars["LIBDIR"]); vars["CPPFLAGS"] = get_variable ("CPPFLAGS", replace_prefix (%OCTAVE_CONF_CPPFLAGS%)); vars["INCFLAGS"] = get_variable ("INCFLAGS", DEFAULT_INCFLAGS); vars["F77"] = get_variable ("F77", %OCTAVE_CONF_MKOCTFILE_F77%); vars["FFLAGS"] = get_variable ("FFLAGS", %OCTAVE_CONF_FFLAGS%); vars["FPICFLAG"] = get_variable ("FPICFLAG", %OCTAVE_CONF_FPICFLAG%); vars["CC"] = get_variable ("CC", %OCTAVE_CONF_MKOCTFILE_CC%); if (verbose && vars["CC"] == "cc-msvc") vars["CC"] += " -d"; vars["CFLAGS"] = get_variable ("CFLAGS", %OCTAVE_CONF_CFLAGS%); vars["CPICFLAG"] = get_variable ("CPICFLAG", %OCTAVE_CONF_CPICFLAG%); vars["CXX"] = get_variable ("CXX", %OCTAVE_CONF_MKOCTFILE_CXX%); if (verbose && vars["CXX"] == "cc-msvc") vars["CXX"] += " -d"; vars["CXXFLAGS"] = get_variable ("CXXFLAGS", %OCTAVE_CONF_CXXFLAGS%); vars["CXXLD"] = get_variable ("CXXLD", vars["CXX"]); if (verbose && vars["CXXLD"] == "cc-msvc") vars["CXXLD"] += " -d"; vars["CXXPICFLAG"] = get_variable ("CXXPICFLAG", %OCTAVE_CONF_CXXPICFLAG%); vars["XTRA_CFLAGS"] = get_variable ("XTRA_CFLAGS", %OCTAVE_CONF_XTRA_CFLAGS%); vars["XTRA_CXXFLAGS"] = get_variable ("XTRA_CXXFLAGS", %OCTAVE_CONF_XTRA_CXXFLAGS%); vars["AR"] = get_variable ("AR", %OCTAVE_CONF_MKOCTFILE_AR%); vars["RANLIB"] = get_variable ("RANLIB", %OCTAVE_CONF_MKOCTFILE_RANLIB%); vars["DEPEND_FLAGS"] = get_variable ("DEPEND_FLAGS", %OCTAVE_CONF_DEPEND_FLAGS%); vars["DEPEND_EXTRA_SED_PATTERN"] = get_variable ("DEPEND_EXTRA_SED_PATTERN", %OCTAVE_CONF_DEPEND_EXTRA_SED_PATTERN%); vars["DL_LDFLAGS"] = get_variable ("DL_LDFLAGS", %OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%); if (! link_stand_alone) DEFAULT_LDFLAGS += ' ' + vars["DL_LDFLAGS"]; vars["RDYNAMIC_FLAG"] = get_variable ("RDYNAMIC_FLAG", %OCTAVE_CONF_RDYNAMIC_FLAG%); vars["LIBOCTAVE"] = "-loctave"; vars["LIBOCTINTERP"] = "-loctinterp"; vars["READLINE_LIBS"] = "-lreadline"; vars["LAPACK_LIBS"] = get_variable ("LAPACK_LIBS", %OCTAVE_CONF_LAPACK_LIBS%); vars["BLAS_LIBS"] = get_variable ("BLAS_LIBS", %OCTAVE_CONF_BLAS_LIBS%); vars["FFTW3_LDFLAGS"] = get_variable ("FFTW3_LDFLAGS", replace_prefix (%OCTAVE_CONF_FFTW3_LDFLAGS%)); vars["FFTW3_LIBS"] = get_variable ("FFTW3_LIBS", %OCTAVE_CONF_FFTW3_LIBS%); vars["FFTW3F_LDFLAGS"] = get_variable ("FFTW3F_LDFLAGS", replace_prefix (%OCTAVE_CONF_FFTW3F_LDFLAGS%)); vars["FFTW3F_LIBS"] = get_variable ("FFTW3F_LIBS", %OCTAVE_CONF_FFTW3F_LIBS%); vars["LIBS"] = get_variable ("LIBS", %OCTAVE_CONF_LIBS%); vars["FLIBS"] = get_variable ("FLIBS", replace_prefix (%OCTAVE_CONF_FLIBS%)); vars["OCTAVE_LINK_DEPS"] = get_variable ("OCTAVE_LINK_DEPS", %OCTAVE_CONF_MKOCTFILE_OCTAVE_LINK_DEPS%); vars["OCTAVE_LINK_OPTS"] = get_variable ("OCTAVE_LINK_OPTS", %OCTAVE_CONF_OCTAVE_LINK_OPTS%); vars["OCT_LINK_DEPS"] = get_variable ("OCT_LINK_DEPS", %OCTAVE_CONF_MKOCTFILE_OCT_LINK_DEPS%); vars["OCT_LINK_OPTS"] = get_variable ("OCT_LINK_OPTS", replace_prefix (%OCTAVE_CONF_OCT_LINK_OPTS%)); vars["LDFLAGS"] = get_variable ("LDFLAGS", DEFAULT_LDFLAGS); vars["LD_STATIC_FLAG"] = get_variable ("LD_STATIC_FLAG", %OCTAVE_CONF_LD_STATIC_FLAG%); // FIXME: Remove LFLAGS in Octave 9 vars["LFLAGS"] = get_variable ("LFLAGS", DEFAULT_LDFLAGS); if (vars["LFLAGS"] != DEFAULT_LDFLAGS) std::cerr << "mkoctfile: warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl; vars["F77_INTEGER8_FLAG"] = get_variable ("F77_INTEGER8_FLAG", %OCTAVE_CONF_F77_INTEGER_8_FLAG%); vars["ALL_FFLAGS"] = vars["FFLAGS"] + ' ' + vars["F77_INTEGER8_FLAG"]; if (debug) vars["ALL_FFLAGS"] += " -g"; vars["ALL_CFLAGS"] = vars["INCFLAGS"] + ' ' + vars["XTRA_CFLAGS"] + ' ' + vars["CFLAGS"]; if (debug) vars["ALL_CFLAGS"] += " -g"; vars["ALL_CXXFLAGS"] = vars["INCFLAGS"] + ' ' + vars["XTRA_CXXFLAGS"] + ' ' + vars["CXXFLAGS"]; if (debug) vars["ALL_CXXFLAGS"] += " -g"; vars["ALL_LDFLAGS"] = vars["LD_STATIC_FLAG"] + ' ' + vars["CPICFLAG"] + ' ' + vars["LDFLAGS"]; vars["OCTAVE_LIBS"] = (vars["LIBOCTINTERP"] + ' ' + vars["LIBOCTAVE"] + ' ' + vars["SPECIAL_MATH_LIB"]); vars["FFTW_LIBS"] = vars["FFTW3_LDFLAGS"] + ' ' + vars["FFTW3_LIBS"] + ' ' + vars["FFTW3F_LDFLAGS"] + ' ' + vars["FFTW3F_LIBS"]; return vars; } static std::string usage_msg = "usage: mkoctfile [options] file ..."; static std::string version_msg = "mkoctfile, version " OCTAVE_VERSION; static std::string help_msg = "\n" "Options:\n" "\n" " -h, -?, --help Print this message.\n" "\n" " -IDIR Add -IDIR to compile commands.\n" "\n" " -idirafter DIR Add -idirafter DIR to compile commands.\n" "\n" " -DDEF Add -DDEF to compile commands.\n" "\n" " -lLIB Add library LIB to link command.\n" "\n" " -LDIR Add -LDIR to link command.\n" "\n" " -M, --depend Generate dependency files (.d) for C and C++\n" " source files.\n" #if ! defined (OCTAVE_USE_WINDOWS_API) "\n" " -pthread Add -pthread to link command.\n" #endif "\n" " -RDIR Add -RDIR to link command.\n" "\n" " -Wl,... Pass flags though the linker like -Wl,-rpath=...\n" "\n" " -W... Pass flags though the compiler like -Wa,OPTION.\n" "\n" " -c, --compile Compile, but do not link.\n" "\n" " -o FILE, --output FILE Output filename. Default extension is .oct\n" " (or .mex if --mex is specified) unless linking\n" " a stand-alone executable.\n" "\n" " -g Enable debugging options for compilers.\n" "\n" " -p VAR, --print VAR Print configuration variable VAR. There are\n" " three categories of variables:\n" "\n" " Octave configuration variables that users may\n" " override with environment variables. These are\n" " used in commands that mkoctfile executes.\n" "\n" " ALL_CFLAGS INCLUDEDIR\n" " ALL_CXXFLAGS LAPACK_LIBS\n" " ALL_FFLAGS LDFLAGS\n" " ALL_LDFLAGS LD_STATIC_FLAG\n" " BLAS_LIBS LIBDIR\n" " CC LIBOCTAVE\n" " CFLAGS LIBOCTINTERP\n" " CPICFLAG OCTAVE_LINK_OPTS\n" " CPPFLAGS OCTINCLUDEDIR\n" " CXX OCTAVE_LIBS\n" " CXXFLAGS OCTAVE_LINK_DEPS\n" " CXXLD OCTLIBDIR\n" " CXXPICFLAG OCT_LINK_DEPS\n" " DL_LDFLAGS OCT_LINK_OPTS\n" " F77 RDYNAMIC_FLAG\n" " F77_INTEGER8_FLAG SPECIAL_MATH_LIB\n" " FFLAGS XTRA_CFLAGS\n" " FPICFLAG XTRA_CXXFLAGS\n" " INCFLAGS\n" "\n" " Octave configuration variables as above, but\n" " currently unused by mkoctfile.\n" "\n" " AR\n" " DEPEND_EXTRA_SED_PATTERN\n" " DEPEND_FLAGS\n" " FFTW3F_LDFLAGS\n" " FFTW3F_LIBS\n" " FFTW3_LDFLAGS\n" " FFTW3_LIBS\n" " FFTW_LIBS\n" " FLIBS\n" " LIBS\n" " RANLIB\n" " READLINE_LIBS\n" "\n" " Octave configuration variables that are provided\n" " for informational purposes only. Except for\n" " OCTAVE_HOME and OCTAVE_EXEC_HOME, users may not\n" " override these variables.\n" "\n" " If OCTAVE_HOME or OCTAVE_EXEC_HOME are set in\n" " the environment, then other variables are adjusted\n" " accordingly with OCTAVE_HOME or OCTAVE_EXEC_HOME\n" " substituted for the original value of the directory\n" " specified by the --prefix or --exec-prefix options\n" " that were used when Octave was configured.\n" "\n" " API_VERSION LOCALFCNFILEDIR\n" " ARCHLIBDIR LOCALOCTFILEDIR\n" " BINDIR LOCALSTARTUPFILEDIR\n" " CANONICAL_HOST_TYPE LOCALVERARCHLIBDIR\n" " DATADIR LOCALVERFCNFILEDIR\n" " DATAROOTDIR LOCALVEROCTFILEDIR\n" " DEFAULT_PAGER MAN1DIR\n" " EXEC_PREFIX MAN1EXT\n" " EXEEXT MANDIR\n" " FCNFILEDIR OCTAVE_EXEC_HOME\n" " IMAGEDIR OCTAVE_HOME\n" " INFODIR OCTAVE_VERSION\n" " INFOFILE OCTDATADIR\n" " LIBEXECDIR OCTDOCDIR\n" " LOCALAPIARCHLIBDIR OCTFILEDIR\n" " LOCALAPIFCNFILEDIR OCTFONTSDIR\n" " LOCALAPIOCTFILEDIR STARTUPFILEDIR\n" " LOCALARCHLIBDIR\n" "\n" " --link-stand-alone Link a stand-alone executable file.\n" "\n" " --mex Assume we are creating a MEX file. Set the\n" " default output extension to \".mex\".\n" "\n" " -s, --strip Strip output file.\n" "\n" " -n, --just-print, --dry-run\n" " Print commands, but do not execute them.\n" "\n" " -v, --verbose Echo commands as they are executed.\n" "\n" " --silent Ignored. Intended to suppress output from\n" " compiler steps.\n" "\n" " FILE Compile or link FILE. Recognized file types are:\n" "\n" " .c C source\n" " .cc C++ source\n" " .cp C++ source\n" " .cpp C++ source\n" " .CPP C++ source\n" " .cxx C++ source\n" " .c++ C++ source\n" " .C C++ source\n" " .f Fortran source (fixed form)\n" " .F Fortran source (fixed form)\n" " .f90 Fortran source (free form)\n" " .F90 Fortran source (free form)\n" " .o object file\n" " .a library file\n" #if defined (_MSC_VER) " .lib library file\n" #endif "\n"; static std::string basename (const std::string& s, bool strip_path = false) { std::string retval; std::size_t pos = s.rfind ('.'); if (pos == std::string::npos) retval = s; else retval = s.substr (0, pos); if (strip_path) { std::size_t p1 = retval.rfind ('/'), p2 = retval.rfind ('\\'); pos = (p1 != std::string::npos && p2 != std::string::npos ? std::max (p1, p2) : (p2 != std::string::npos ? p2 : p1)); if (pos != std::string::npos) retval = retval.substr (++pos, std::string::npos); } return retval; } inline bool starts_with (const std::string& s, const std::string& prefix) { return (s.length () >= prefix.length () && s.find (prefix) == 0); } inline bool ends_with (const std::string& s, const std::string& suffix) { return (s.length () >= suffix.length () && s.rfind (suffix) == s.length () - suffix.length ()); } static int run_command (const std::string& cmd, bool verbose, bool printonly = false) { if (printonly) { std::cout << cmd << std::endl; return 0; } if (verbose) std::cout << cmd << std::endl; // FIXME: Call _wsystem on Windows or octave::sys::system. int result = system (cmd.c_str ()); if (octave_wifexited_wrapper (result)) result = octave_wexitstatus_wrapper (result); return result; } bool is_true (const std::string& s) { return (s == "yes" || s == "true"); } static std::string get_temp_directory (void) { std::string tempd; tempd = octave_getenv ("TMPDIR"); #if defined (__MINGW32__) || defined (_MSC_VER) if (tempd.empty ()) tempd = octave_getenv ("TEMP"); if (tempd.empty ()) tempd = octave_getenv ("TMP"); #if defined (P_tmpdir) if (tempd.empty ()) tempd = P_tmpdir; #endif // Some versions of MinGW and MSVC either don't define P_tmpdir, or // define it to a single backslash. In such cases just use C:\temp. if (tempd.empty () || tempd == R"(\)") tempd = R"(c:\temp)"; #else #if defined (P_tmpdir) if (tempd.empty ()) tempd = P_tmpdir; #else if (tempd.empty ()) tempd = "/tmp"; #endif #endif return tempd; } static std::string create_interleaved_complex_file (void) { std::string tmpl = get_temp_directory () + "/oct-XXXXXX.c"; char *ctmpl = new char [tmpl.length () + 1]; ctmpl = strcpy (ctmpl, tmpl.c_str ()); // mkostemps will open the file and return a file descriptor. We // won't worry about closing it because we will need the file until we // are done and then the file will be closed when mkoctfile exits. int fd = octave_mkostemps_wrapper (ctmpl, 2); // Make C++ string from filled-in template. std::string retval (ctmpl); delete [] ctmpl; // Write symbol definition to file. FILE *fid = fdopen (fd, "w"); fputs ("const int __mx_has_interleaved_complex__ = 1;\n", fid); fclose (fid); return retval; } static std::string tmp_objfile_name (void) { std::string tmpl = get_temp_directory () + "/oct-XXXXXX.o"; char *ctmpl = new char [tmpl.length () + 1]; ctmpl = strcpy (ctmpl, tmpl.c_str ()); // mkostemps will open the file and return a file descriptor. We // won't worry about closing it because we will need the file until we // are done and then the file will be closed when mkoctfile exits. octave_mkostemps_wrapper (ctmpl, 2); std::string retval (ctmpl); // make C++ string from filled-in template delete [] ctmpl; return retval; } static void clean_up_tmp_files (const std::list<std::string>& tmp_files) { for (const auto& file : tmp_files) octave_unlink_wrapper (file.c_str ()); } #if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE) extern "C" int wmain (int argc, wchar_t **sys_argv) { std::vector<std::string> argv; // Convert wide character strings to multibyte UTF-8 strings and save // them in a vector of std::string objects for later processing. std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv; for (int i_arg = 0; i_arg < argc; i_arg++) argv.push_back (wchar_conv.to_bytes (sys_argv[i_arg])); #else int main (int argc, char **sys_argv) { std::vector<std::string> argv; // Save args as vector of std::string objects for later processing. for (int i_arg = 0; i_arg < argc; i_arg++) argv.push_back (sys_argv[i_arg]); #endif if (argc == 1) { std::cout << usage_msg << std::endl; return 1; } if (argc == 2 && (argv[1] == "-v" || argv[1] == "-version" || argv[1] == "--version")) { std::cout << version_msg << std::endl; return 0; } std::list<std::string> cfiles, ccfiles, f77files, tmp_objfiles; std::string output_ext = ".oct"; std::string objfiles, libfiles, octfile, outputfile; std::string incflags, defs, ldflags, pass_on_options; std::string var_to_print; bool debug = false; bool verbose = false; bool strip = false; bool no_oct_file_strip_on_this_platform = is_true ("%NO_OCT_FILE_STRIP%"); bool compile_only = false; bool link_stand_alone = false; bool depend = false; bool printonly = false; bool output_file_option = false; bool creating_mex_file = false; bool r2017b_option = false; bool r2018a_option = false; // The default for this may change in the future. bool mx_has_interleaved_complex = false; for (int i = 1; i < argc; i++) { std::string arg = argv[i]; std::string file; if (ends_with (arg, ".c")) { file = arg; cfiles.push_back (file); } else if (ends_with (arg, ".cc") || ends_with (arg, ".cp") || ends_with (arg, ".cpp") || ends_with (arg, ".CPP") || ends_with (arg, ".cxx") || ends_with (arg, ".c++") || ends_with (arg, ".C")) { file = arg; ccfiles.push_back (file); } else if (ends_with (arg, ".f") || ends_with (arg, ".F") || ends_with (arg, "f90") || ends_with (arg, ".F90")) { file = arg; f77files.push_back (file); } else if (ends_with (arg, ".o") || ends_with (arg, ".obj")) { file = arg; objfiles += (' ' + quote_path (arg)); } else if (ends_with (arg, ".lib") || ends_with (arg, ".a")) { file = arg; libfiles += (' ' + quote_path (arg)); } else if (arg == "-d" || arg == "-debug" || arg == "--debug" || arg == "-v" || arg == "-verbose" || arg == "--verbose") { verbose = true; } else if (arg == "-silent" || arg == "--silent") { // Ignored for now. } else if (arg == "-h" || arg == "-?" || arg == "-help" || arg == "--help") { std::cout << usage_msg << std::endl; std::cout << help_msg << std::endl; return 0; } else if (starts_with (arg, "-I")) { incflags += (' ' + quote_path (arg)); } else if (arg == "-idirafter") { if (i < argc-1) { arg = argv[++i]; incflags += (" -idirafter " + arg); } else std::cerr << "mkoctfile: include directory name missing" << std::endl; } else if (starts_with (arg, "-D")) { defs += (' ' + arg); } else if (arg == "-largeArrayDims" || arg == "-compatibleArrayDims") { std::cerr << "mkoctfile: warning: -largeArrayDims and -compatibleArrayDims are accepted for compatibility, but ignored" << std::endl; } else if (arg == "-R2017b") { if (r2018a_option) { std::cerr << "mkoctfile: only one of -R2017b and -R2018a may be used" << std::endl; return 1; } r2017b_option = true; } else if (arg == "-R2018a") { if (r2017b_option) { std::cerr << "mkoctfile: only one of -R2017b and -R2018a may be used" << std::endl; return 1; } r2018a_option = true; mx_has_interleaved_complex = true; } else if (starts_with (arg, "-Wl,") || starts_with (arg, "-l") || starts_with (arg, "-L") || starts_with (arg, "-R")) { ldflags += (' ' + quote_path (arg)); } #if ! defined (OCTAVE_USE_WINDOWS_API) else if (arg == "-pthread") { ldflags += (' ' + arg); } #endif else if (arg == "-M" || arg == "-depend" || arg == "--depend") { depend = true; } else if (arg == "-o" || arg == "-output" || arg == "--output") { output_file_option = true; if (i < argc-1) { arg = argv[++i]; outputfile = arg; } else std::cerr << "mkoctfile: output filename missing" << std::endl; } else if (arg == "-n" || arg == "--dry-run" || arg == "--just-print") { printonly = true; } else if (arg == "-p" || arg == "-print" || arg == "--print") { if (i < argc-1) { ++i; // FIXME: Remove LFLAGS checking in Octave 9 if (argv[i] == "LFLAGS") std::cerr << "mkoctfile: warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl; if (! var_to_print.empty ()) std::cerr << "mkoctfile: warning: only one '" << arg << "' option will be processed" << std::endl; else var_to_print = argv[i]; } else std::cerr << "mkoctfile: --print requires argument" << std::endl; } else if (arg == "-s" || arg == "-strip" || arg == "--strip") { if (no_oct_file_strip_on_this_platform) std::cerr << "mkoctfile: stripping disabled on this platform" << std::endl; else strip = true; } else if (arg == "-c" || arg == "-compile" || arg == "--compile") { compile_only = true; } else if (arg == "-g") { debug = true; } else if (arg == "-link-stand-alone" || arg == "--link-stand-alone") { link_stand_alone = true; } else if (arg == "-mex" || arg == "--mex") { creating_mex_file = true; incflags += " -I."; #if defined (_MSC_VER) ldflags += " -Wl,-export:mexFunction"; #endif output_ext = ".mex"; } else if (starts_with (arg, "-W")) { pass_on_options += (' ' + arg); } else if (starts_with (arg, "-O")) { pass_on_options += (' ' + arg); } else if (starts_with (arg, "-")) { // Pass through any unrecognized options. pass_on_options += (' ' + arg); // Check for an additional argument following the option. // However, don't check the final position which is typically a file if (i < argc-2) { arg = argv[i+1]; if (arg[0] != '-') { pass_on_options += (' ' + arg); i++; } } } else { std::cerr << "mkoctfile: unrecognized argument " << arg << std::endl; return 1; } if (! file.empty () && octfile.empty ()) octfile = file; } std::map<std::string, std::string> vars = make_vars_map (link_stand_alone, verbose, debug); if (! var_to_print.empty ()) { if (vars.find (var_to_print) == vars.end ()) { std::cerr << "mkoctfile: unknown variable '" << var_to_print << "'" << std::endl; return 1; } std::cout << vars[var_to_print] << std::endl; return 0; } if (creating_mex_file) { if (vars["ALL_CFLAGS"].find ("-g") != std::string::npos) defs += " -DMEX_DEBUG"; if (mx_has_interleaved_complex) { defs += " -DMX_HAS_INTERLEAVED_COMPLEX=1"; if (! compile_only) { // Create tmp C source file that defines an extern symbol // that can be checked when loading the mex file to // determine that the file was compiled expecting // interleaved complex values. std::string tmp_file = create_interleaved_complex_file (); cfiles.push_back (tmp_file); } } } else { if (r2017b_option) std::cerr << "mkoctfile: warning: -R2017b option ignored unless creating mex file" << std::endl; if (r2018a_option) std::cerr << "mkoctfile: warning: -R2018a option ignored unless creating mex file" << std::endl; } if (compile_only && output_file_option && (cfiles.size () + ccfiles.size () + f77files.size ()) > 1) { std::cerr << "mkoctfile: may not use -c and -o with multiple source files" << std::endl; return 1; } std::string output_option; if (link_stand_alone) { if (! outputfile.empty ()) output_option = "-o " + outputfile; } else { if (! outputfile.empty ()) { // FIXME: should probably do a better job of finding the // filename extension instead of just looking at the filename // length. octfile = outputfile; std::size_t len = octfile.length (); std::size_t len_ext = output_ext.length (); if (len <= len_ext || octfile.substr (len-len_ext) != output_ext) octfile += output_ext; } else octfile = basename (octfile, true) + output_ext; } if (depend) { #if defined (OCTAVE_USE_WINDOWS_API) && ! defined (_UNICODE) std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv; #endif for (const auto& f : cfiles) { std::string dfile = basename (f, true) + ".d", line; octave_unlink_wrapper (dfile.c_str ()); std::string cmd = (vars["CC"] + ' ' + vars["DEPEND_FLAGS"] + ' ' + vars["CPPFLAGS"] + ' ' + vars["ALL_CFLAGS"] + ' ' + incflags + ' ' + defs + ' ' + quote_path (f)); #if defined (OCTAVE_USE_WINDOWS_API) FILE *fd; try { std::wstring wcmd = wchar_conv.from_bytes (cmd); fd = ::_wpopen (wcmd.c_str (), L"r"); } catch (const std::range_error& e) { fd = ::popen (cmd.c_str (), "r"); } std::ofstream fo; try { std::wstring wfile = wchar_conv.from_bytes (dfile); fo.open (wfile.c_str ()); } catch (const std::range_error& e) { fo.open (dfile.c_str ()); } #else FILE *fd = popen (cmd.c_str (), "r"); std::ofstream fo (dfile.c_str ()); #endif std::size_t pos; while (! feof (fd)) { line = get_line (fd); if ((pos = line.rfind (".o:")) != std::string::npos) { std::size_t spos = line.rfind ('/', pos); std::string ofile = (spos == std::string::npos ? line.substr (0, pos+2) : line.substr (spos+1, pos-spos+1)); fo << "pic/" << ofile << ' ' << ofile << ' ' << dfile << line.substr (pos) << std::endl; } else fo << line << std::endl; } pclose (fd); fo.close (); } for (const auto& f : ccfiles) { std::string dfile = basename (f, true) + ".d", line; octave_unlink_wrapper (dfile.c_str ()); std::string cmd = (vars["CXX"] + ' ' + vars["DEPEND_FLAGS"] + ' ' + vars["CPPFLAGS"] + ' ' + vars["ALL_CXXFLAGS"] + ' ' + incflags + ' ' + defs + ' ' + quote_path (f)); #if defined (OCTAVE_USE_WINDOWS_API) FILE *fd; try { std::wstring wcmd = wchar_conv.from_bytes (cmd); fd = ::_wpopen (wcmd.c_str (), L"r"); } catch (const std::range_error& e) { fd = ::popen (cmd.c_str (), "r"); } std::ofstream fo; try { std::wstring wfile = wchar_conv.from_bytes (dfile); fo.open (wfile.c_str ()); } catch (const std::range_error& e) { fo.open (dfile.c_str ()); } #else FILE *fd = popen (cmd.c_str (), "r"); std::ofstream fo (dfile.c_str ()); #endif std::size_t pos; while (! feof (fd)) { line = get_line (fd); if ((pos = line.rfind (".o:")) != std::string::npos) { std::size_t spos = line.rfind ('/', pos); std::string ofile = (spos == std::string::npos ? line.substr (0, pos+2) : line.substr (spos+1, pos-spos+1)); fo << "pic/" << ofile << ' ' << ofile << ' ' << dfile << line.substr (pos+2) << std::endl; } else fo << line << std::endl; } pclose (fd); fo.close (); } return 0; } for (const auto& f : f77files) { if (! vars["F77"].empty ()) { std::string o; if (compile_only) { if (! outputfile.empty ()) o = outputfile; else o = basename (f, true) + ".o"; } else { o = tmp_objfile_name (); tmp_objfiles.push_back (o); objfiles += (' ' + o); } std::string cmd = (vars["F77"] + " -c " + vars["FPICFLAG"] + ' ' + vars["ALL_FFLAGS"] + ' ' + incflags + ' ' + defs + ' ' + pass_on_options + ' ' + quote_path (f) + " -o " + quote_path (o)); int status = run_command (cmd, verbose, printonly); if (status) return status; } else { std::cerr << "mkoctfile: no way to compile Fortran file " << f << std::endl; return 1; } } for (const auto& f : cfiles) { if (! vars["CC"].empty ()) { std::string o; if (compile_only) { if (! outputfile.empty ()) o = outputfile; else o = basename (f, true) + ".o"; } else { o = tmp_objfile_name (); tmp_objfiles.push_back (o); objfiles += (' ' + o); } std::string cmd = (vars["CC"] + " -c " + vars["CPPFLAGS"] + ' ' + vars["CPICFLAG"] + ' ' + vars["ALL_CFLAGS"] + ' ' + pass_on_options + ' ' + incflags + ' ' + defs + ' ' + quote_path (f) + " -o " + quote_path (o)); int status = run_command (cmd, verbose, printonly); if (status) return status; } else { std::cerr << "mkoctfile: no way to compile C file " << f << std::endl; return 1; } } for (const auto& f : ccfiles) { if (! vars["CXX"].empty ()) { std::string o; if (compile_only) { if (! outputfile.empty ()) o = outputfile; else o = basename (f, true) + ".o"; } else { o = tmp_objfile_name (); tmp_objfiles.push_back (o); objfiles += (' ' + o); } std::string cmd = (vars["CXX"] + " -c " + vars["CPPFLAGS"] + ' ' + vars["CXXPICFLAG"] + ' ' + vars["ALL_CXXFLAGS"] + ' ' + pass_on_options + ' ' + incflags + ' ' + defs + ' ' + quote_path (f) + " -o " + quote_path (o)); int status = run_command (cmd, verbose, printonly); if (status) return status; } else { std::cerr << "mkoctfile: no way to compile C++ file " << f << std::endl; return 1; } } // If we are only compiling, we are done. if (compile_only) return 0; if (objfiles.empty ()) { std::cerr << "mkoctfile: no objects to link" << std::endl; return 1; } std::string octave_libs; if (link_stand_alone) { if (! vars["CXXLD"].empty ()) { octave_libs = "-L" + quote_path (vars["OCTLIBDIR"]) + ' ' + vars["OCTAVE_LIBS"]; // FIXME: Remove LFLAGS in Octave 9 std::string cmd = (vars["CXXLD"] + ' ' + vars["CPPFLAGS"] + ' ' + vars["ALL_CXXFLAGS"] + ' ' + vars["RDYNAMIC_FLAG"] + ' ' + pass_on_options + ' ' + output_option + ' ' + objfiles + ' ' + libfiles + ' ' + ldflags + ' ' + vars["ALL_LDFLAGS"] + ' ' + vars["LFLAGS"] + ' ' + octave_libs + ' ' + vars["OCTAVE_LINK_OPTS"] + ' ' + vars["OCTAVE_LINK_DEPS"]); int status = run_command (cmd, verbose, printonly); clean_up_tmp_files (tmp_objfiles); if (status) return status; } else { std::cerr << "mkoctfile: no way to link stand-alone executable file" << std::endl; return 1; } } else { #if defined (OCTAVE_USE_WINDOWS_API) || defined(CROSS) octave_libs = "-L" + quote_path (vars["OCTLIBDIR"]) + ' ' + vars["OCTAVE_LIBS"]; #endif // FIXME: Remove LFLAGS in Octave 9 std::string cmd = (vars["CXXLD"] + ' ' + vars["ALL_CXXFLAGS"] + ' ' + pass_on_options + " -o " + octfile + ' ' + objfiles + ' ' + libfiles + ' ' + ldflags + ' ' + vars["DL_LDFLAGS"] + ' ' + vars["LDFLAGS"] + ' ' + vars["LFLAGS"] + ' ' + octave_libs + ' ' + vars["OCT_LINK_OPTS"] + ' ' + vars["OCT_LINK_DEPS"]); #if defined (OCTAVE_USE_WINDOWS_API) || defined(CROSS) if (! f77files.empty () && ! vars["FLIBS"].empty ()) cmd += ' ' + vars["FLIBS"]; #endif int status = run_command (cmd, verbose, printonly); clean_up_tmp_files (tmp_objfiles); if (status) return status; } if (strip) { std::string cmd = "strip " + octfile; int status = run_command (cmd, verbose, printonly); if (status) return status; } return 0; }