c5e29ad23d
-Z7 writes all debug info into the .obj file, so it avoids the .pdb altogether. Change-Id: I89265009782d0a901ba3583a7241da0daf83860e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129877 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
332 lines
10 KiB
C++
332 lines
10 KiB
C++
/* -*- 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: */
|