diff options
Diffstat (limited to 'solenv/gcc-wrappers/wrapper.cxx')
-rw-r--r-- | solenv/gcc-wrappers/wrapper.cxx | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/solenv/gcc-wrappers/wrapper.cxx b/solenv/gcc-wrappers/wrapper.cxx new file mode 100644 index 000000000..c84fd4990 --- /dev/null +++ b/solenv/gcc-wrappers/wrapper.cxx @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* +* This file is part of the LibreOffice project. +* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#include "wrapper.hxx" + +#define WIN32_LEAN_AND_MEAN + +#include <windows.h> + +#define BUFLEN 2048 + +std::string getexe(std::string exename, bool maybeempty) { + char* cmdbuf; + size_t cmdlen; + _dupenv_s(&cmdbuf,&cmdlen,exename.c_str()); + if(!cmdbuf) { + if (maybeempty) { + return std::string(); + } + std::cout << "Error " << exename << " not defined. Did you forget to source the environment?" << std::endl; + exit(1); + } + std::string command(cmdbuf); + free(cmdbuf); + return command; +} + +void setupccenv() { + // Set-up library path + std::string libpath="LIB="; + char* libbuf; + size_t liblen; + _dupenv_s(&libbuf,&liblen,"ILIB"); + if (libbuf == nullptr) { + std::cerr << "No environment variable ILIB" << std::endl; + std::exit(EXIT_FAILURE); + } + libpath.append(libbuf); + free(libbuf); + if(_putenv(libpath.c_str())<0) { + std::cerr << "Error: could not export LIB" << std::endl; + exit(1); + } + + // Set-up include path + std::string includepath="INCLUDE=."; + char* incbuf; + size_t inclen; + _dupenv_s(&incbuf,&inclen,"SOLARINC"); + if (incbuf == nullptr) { + std::cerr << "No environment variable SOLARINC" << std::endl; + std::exit(EXIT_FAILURE); + } + std::string inctmp(incbuf); + free(incbuf); + + // 2 = strlen("-I") + for(size_t pos=0,len=0;pos<inctmp.length();) { + while (pos != inctmp.length() && inctmp[pos] == ' ') { + ++pos; + } + size_t endpos=inctmp.find(" -I",pos+1); + if(endpos==std::string::npos) + endpos=inctmp.length(); + len=endpos-pos; + + while(len>0&&inctmp[pos+len-1]==' ') + --len; + + if(len>2) { + includepath.append(";"); + includepath.append(inctmp,pos+2,len-2); + } + pos=endpos; + } + if(_putenv(includepath.c_str())<0) { + std::cerr << "Error: could not export INCLUDE" << std::endl; + exit(1); + } +} + +std::string processccargs(const std::vector<std::string>& rawargs, std::string &env_prefix, bool &verbose) +{ + // default env var prefix + env_prefix = "REAL_"; + verbose = false; + bool env_prefix_next_arg = false; + + // suppress the msvc banner + std::string args=" -nologo"; + // TODO: should these options be enabled globally? + args.append(" -EHsc"); + const char *const pDebugRuntime(getenv("MSVC_USE_DEBUG_RUNTIME")); + if (pDebugRuntime && !strcmp(pDebugRuntime, "TRUE")) + args.append(" -MDd"); + else + args.append(" -MD"); + args.append(" -Gy"); + args.append(" -Ob1 -Oxs -Oy-"); + + std::string linkargs; + bool block_linkargs = false; + + // Instead of using synced PDB access (-FS), use individual PDB files based on output. + // In fact, simply use -Z7, which doesn't use PDB files at all and writes all debug into the .obj file. + const char *const pEnvIndividualPDBs(getenv("MSVC_USE_INDIVIDUAL_PDBS")); + const bool bIndividualPDBs = (pEnvIndividualPDBs && !strcmp(pEnvIndividualPDBs, "TRUE")); + const char *const pEnvEnableZ7Debug(getenv("ENABLE_Z7_DEBUG")); + const bool bEnableZ7Debug = (pEnvEnableZ7Debug && !strcmp(pEnvEnableZ7Debug, "TRUE")) || bIndividualPDBs; + + for(std::vector<std::string>::const_iterator i = rawargs.begin(); i != rawargs.end(); ++i) { + if (env_prefix_next_arg) + { + env_prefix = *i; + env_prefix_next_arg = false; + continue; + } + + args.append(" "); + if(*i == "-o") { + // TODO: handle more than just exe output + ++i; + size_t dot=(*i).find_last_of("."); + if(!(*i).compare(dot+1,3,"obj") || !(*i).compare(dot+1,1,"o")) + { + args.append("-Fo"); + args.append(*i); + } + else if(!(*i).compare(dot+1,3,"exe")) + { + args.append("-Fe"); + args.append(*i); + } + else if(!(*i).compare(dot+1,3,"dll")) + { // apparently cl.exe has no flag for dll? + linkargs.append(" -dll -out:"); + linkargs.append(*i); + } + else if (dot == std::string::npos) + { + args.append("-Fe"); + args.append(*i + ".exe"); + } + else + { + std::cerr << "unknown -o argument - please adapt gcc-wrapper for \"" + << (*i) << "\"" << std::endl; + exit(1); + } + } + else if(*i == "-g" || !(*i).compare(0,5,"-ggdb")) { + if(!bEnableZ7Debug) + { + args.append("-Zi"); + args.append(" -FS"); + } + else + { + // ccache doesn't work with -Zi, the -link -debug for linking will create a final PDB + args.append("-Z7"); + } + } + else if(!(*i).compare(0,2,"-D")) { + // need to re-escape strings for preprocessor + std::string str = *i; + for(size_t pos=str.find("\""); pos!=std::string::npos; pos=str.find("\"",pos)) { + str.replace(pos,0,"\\"); + pos+=2; + } + args.append(str); + } + else if(!(*i).compare(0,2,"-L")) { + linkargs.append(" -LIBPATH:"+(*i).substr(2)); + } + else if(!(*i).compare(0,2,"-l") && (*i).compare(0,5,"-link")) { + linkargs.append(" "+(*i).substr(2)+".lib"); + } + else if(!(*i).compare(0,5,"-def:") || !(*i).compare(0,5,"/def:")) { + // why are we invoked with /def:? cl.exe should handle plain + // "foo.def" by itself + linkargs.append(" " + *i); + } + else if(!(*i).compare(0,12,"-fvisibility") || *i == "-fPIC") { + //TODO: drop other gcc-specific options + } + else if(!(*i).compare(0,4,"-Wl,")) { + //TODO: drop other gcc-specific options + } + else if(*i == "-c") { + args.append("-c"); + // If -c is specified, there will be no linking anyway, + // and passing -link with -c stops ccache from caching. + block_linkargs = true; + } + else if(*i == "-Werror") + args.append("-WX"); + else if (*i == "--wrapper-print-cmdline") + verbose = true; + else + { + size_t pos = i->find("="); + if (0 == i->compare(0, pos, "--wrapper-env-prefix")) + { + if (pos == std::string::npos) + env_prefix_next_arg = true; + else if (pos + 1 == i->length()) + { + // bailout - missing arg + env_prefix_next_arg = true; + break; + } + else + env_prefix = i->substr(pos + 1); + } + else + args.append(*i); + } + } + + if (env_prefix_next_arg) + { + std::cerr << "wrapper-env-prefix needs an argument!" << std::endl; + exit(1); + } + + if(!block_linkargs) { + // apparently these must be at the end + // otherwise configure tests may fail + // note: always use -debug so a PDB file is created + args.append(" -link -debug "); + args.append(linkargs); + } + + return args; +} + +int startprocess(std::string command, std::string args, bool verbose) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES sa; + + HANDLE childout_read; + HANDLE childout_write; + + memset(&sa,0,sizeof(sa)); + memset(&si,0,sizeof(si)); + memset(&pi,0,sizeof(pi)); + + sa.nLength=sizeof(sa); + sa.bInheritHandle=TRUE; + + if(!CreatePipe(&childout_read,&childout_write,&sa,0)) { + std::cerr << "Error: could not create stdout pipe" << std::endl; + exit(1); + } + + si.cb=sizeof(si); + si.dwFlags |= STARTF_USESTDHANDLES; + si.hStdOutput=childout_write; + si.hStdError=childout_write; + + // support ccache + size_t pos=command.find("ccache "); + size_t len = strlen("ccache "); + if(pos == std::string::npos) { + pos=command.find("ccache.exe "); + len = strlen("ccache.exe "); + } + if(pos != std::string::npos) { + args.insert(0,command.substr(pos+len)); + command=command.substr(0,pos+len-1); + } + + auto cmdline = "\"" + command + "\" " + args; + + if (verbose) + std::cerr << "CMD= " << command << " " << args << std::endl; + + // Commandline may be modified by CreateProcess + char* cmdlineBuf=_strdup(cmdline.c_str()); + + if(!CreateProcess(nullptr, // Process Name + cmdlineBuf, // Command Line + nullptr, // Process Handle not Inheritable + nullptr, // Thread Handle not Inheritable + TRUE, // Handles are Inherited + 0, // No creation flags + nullptr, // Environment for process + nullptr, // Use same starting directory + &si, // Startup Info + &pi) // Process Information + ) { + auto const e = GetLastError(); + std::cerr << "Error: could not create process \"" << cmdlineBuf << "\": " << e << std::endl; + exit(1); + } + + // if you don't close this the process will hang + CloseHandle(childout_write); + + // Get Process output + char buffer[BUFLEN]; + DWORD readlen, writelen, ret; + HANDLE stdout_handle=GetStdHandle(STD_OUTPUT_HANDLE); + while(true) { + int success=ReadFile(childout_read,buffer,BUFLEN,&readlen,nullptr); + // check if the child process has exited + if(GetLastError()==ERROR_BROKEN_PIPE) + break; + if(!success) { + std::cerr << "Error: could not read from subprocess stdout" << std::endl; + exit(1); + } + if(readlen!=0) { + WriteFile(stdout_handle,buffer,readlen,&writelen,nullptr); + } + } + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &ret); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + return int(ret); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |