Mercurial > mxe-octave
diff src/build-msvctools/gfortran-msvc.cc @ 3061:f8299bb6c872
Initial support for native MSVC compilation.
* add MSVC support files: compiler wrappers and support libraries
* adapt libiconv to work with MSVC
* adapt gettext to work with MSVC
author | Michael Goffioul <michael.goffioul@gmail.com> |
---|---|
date | Mon, 17 Jun 2013 22:43:11 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/build-msvctools/gfortran-msvc.cc Mon Jun 17 22:43:11 2013 -0400 @@ -0,0 +1,253 @@ +#include <errno.h> +#include <iostream> +#include <fstream> +#include <io.h> +#include <list> +#include <string> +#include <vector> +#include <stdlib.h> +#include <stdio.h> +#include <utility> +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +using namespace std; + +bool verbose = false; + +inline bool starts_with(const string& s, const string& prefix) +{ + return (s.length() >= prefix.length() && s.find(prefix) == 0); +} + +inline bool ends_with(const string& s, const string& suffix) +{ + return (s.length() >= suffix.length() && s.rfind(suffix) == s.length()-suffix.length()); +} + +string quote(const string& s) +{ + if (s.find(' ') != string::npos) + return "\"" + s + "\""; + else + return s; +} + +int do_system(const string& cmd) +{ + if (verbose) + cerr << "Running: " << cmd << endl; + + STARTUPINFO info; + PROCESS_INFORMATION proc; + DWORD result; + + ZeroMemory (&info, sizeof (info)); + info.cb = sizeof (info); + ZeroMemory (&proc, sizeof (proc)); + + if (CreateProcess (NULL, (char*)cmd.c_str (), NULL, NULL, TRUE, 0, NULL, NULL, + &info, &proc)) + { + WaitForSingleObject (proc.hProcess, INFINITE); + GetExitCodeProcess (proc.hProcess, &result); + CloseHandle (proc.hProcess); + CloseHandle (proc.hThread); + } + else + result = (DWORD)-1; + + if (verbose) + cerr << "Result: " << (int)result << endl; + + return result; +} + +int do_system(const list<string>& args) +{ + string cmd; + + for (list<string>::const_iterator it = args.begin(); it != args.end(); ++it) + { + if (!cmd.empty()) + cmd += " "; + cmd += quote(*it); + } + return do_system(cmd); +} + +string get_env_var(const char *name, const char *defval) +{ + char *result = getenv(name); + if (!result || result[0] == '\0') + return string(defval); + return string(result); +} + +inline bool is_source_file (const string& s) +{ + static char* f_ext_list[] = { ".f", ".F", ".f90", ".F90", ".f77", ".F77", 0 }; + + for (int i = 0; f_ext_list[i]; i++) + if (ends_with (s, f_ext_list[i])) + return true; + + return false; +} + +inline string get_object_name (const string& s) +{ + int pos = s.rfind ('.'); + + return s.substr (0, pos) + ".o"; +} + +string get_line(FILE *fp) +{ + static vector<char> buf(100); + int idx = 0; + char c; + + while (1) + { + c = (char)fgetc(fp); + if (c == '\n' || c == EOF) + break; + if (buf.size() <= idx) + buf.resize(buf.size() + 100); + buf[idx++] = c; + } + if (idx == 0) + return string(""); + else + return string(&buf[0], idx); +} + +string de_cygwin_path(const string& s) +{ + string result = s; + + if (starts_with(s, "/cygdrive/")) + { + string cmd = "cygpath -m \"" + s + "\""; + FILE* pout = _popen(cmd.c_str(), "r"); + + if (pout != NULL) + { + result = get_line(pout); + _pclose(pout); + } + } + + return result; +} + +int main (int argc, char **argv) +{ + list<string> args, compiler_opts; + string compiler, gfortran_exe = "gfortran"; + bool do_link = true, has_files = false; + list< pair<string, int> > source_files; + + for (int i = 1; i < argc; i++) + { + string arg (argv[i]); + + args.push_back (arg); + + if (arg == "-c") + do_link = false; + else if (arg == "-v") + { + verbose = true; + args.pop_back (); + } + else if (starts_with (arg, "--gfortran-exe=")) + { + gfortran_exe = arg.substr (15); + } + else if (! starts_with (arg, "-")) + { + has_files = true; + if (is_source_file (arg)) + { + arg = de_cygwin_path (arg); + source_files.push_back (pair<string, int> (arg, args.size () - 1)); + } + } + else if (starts_with (arg, "-D") + || starts_with (arg, "-U") + || starts_with (arg, "-O") + || starts_with (arg, "-f") + || starts_with (arg, "-m")) + compiler_opts.push_back (arg); + } + + if (has_files) + { + if (do_link) + { + if (! source_files.empty ()) + { + // Because the compiler and the linker are different, we need + // to compile the source files separately. + + for (list< pair<string, int> >::const_iterator it = source_files.begin (); + it != source_files.end (); ++it) + { + list<string> cargs (compiler_opts); + string obj_name = get_object_name (it->first); + + cargs.push_front ("-c"); + cargs.push_front ("-ff2c"); + cargs.push_front ("-mstackrealign"); + cargs.push_front ("-mincoming-stack-boundary=2"); + if (verbose) + cargs.push_front ("-v"); + cargs.push_front (gfortran_exe); + cargs.push_back (it->first); + cargs.push_back ("-o"); + cargs.push_back (obj_name); + + int res = do_system (cargs); + + if (res == 0) + { + list<string>::iterator lit = args.begin (); + + for (int i = it->second; i > 0; i--, lit++) + /* nothing */; + *lit = obj_name; + } + else + return res; + } + } + + compiler = "cc-msvc"; + if (verbose) + args.push_front ("-d"); + args.push_back ("-lgfortran-msvc"); + args.push_back ("-lmingwcompat"); + args.push_back ("-lmsvcrt"); + //args.push_back ("-lmsvcrt"); + } + else + { + args.push_front ("-ff2c"); + args.push_front ("-mstackrealign"); + args.push_front ("-mincoming-stack-boundary=2"); + if (verbose) + args.push_front ("-v"); + } + } + + if (compiler.empty ()) + compiler = gfortran_exe; + + args.push_front (compiler); + + int retval = do_system (args); + + return retval; +}