summaryrefslogtreecommitdiffstats
path: root/solenv/gcc-wrappers/wrapper.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--solenv/gcc-wrappers/wrapper.cxx332
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: */