1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include "wrapper.hxx"
12 #define WIN32_LEAN_AND_MEAN
18 std::string
getexe(std::string exename
, bool maybeempty
) {
21 _dupenv_s(&cmdbuf
,&cmdlen
,exename
.c_str());
26 std::cout
<< "Error " << exename
<< " not defined. Did you forget to source the environment?" << std::endl
;
29 std::string
command(cmdbuf
);
35 // Set-up library path
36 std::string libpath
="LIB=";
39 _dupenv_s(&libbuf
,&liblen
,"ILIB");
40 if (libbuf
== nullptr) {
41 std::cerr
<< "No environment variable ILIB" << std::endl
;
42 std::exit(EXIT_FAILURE
);
44 libpath
.append(libbuf
);
46 if(_putenv(libpath
.c_str())<0) {
47 std::cerr
<< "Error: could not export LIB" << std::endl
;
51 // Set-up include path
52 std::string includepath
="INCLUDE=.";
55 _dupenv_s(&incbuf
,&inclen
,"SOLARINC");
56 if (incbuf
== nullptr) {
57 std::cerr
<< "No environment variable SOLARINC" << std::endl
;
58 std::exit(EXIT_FAILURE
);
60 std::string
inctmp(incbuf
);
64 for(size_t pos
=0,len
=0;pos
<inctmp
.length();) {
65 while (pos
!= inctmp
.length() && inctmp
[pos
] == ' ') {
68 size_t endpos
=inctmp
.find(" -I",pos
+1);
69 if(endpos
==std::string::npos
)
70 endpos
=inctmp
.length();
73 while(len
>0&&inctmp
[pos
+len
-1]==' ')
77 includepath
.append(";");
78 includepath
.append(inctmp
,pos
+2,len
-2);
82 if(_putenv(includepath
.c_str())<0) {
83 std::cerr
<< "Error: could not export INCLUDE" << std::endl
;
88 std::string
processccargs(const std::vector
<std::string
>& rawargs
, std::string
&env_prefix
, bool &verbose
)
90 // default env var prefix
93 bool env_prefix_next_arg
= false;
95 // suppress the msvc banner
96 std::string args
=" -nologo";
97 // TODO: should these options be enabled globally?
98 args
.append(" -EHsc");
99 const char *const pDebugRuntime(getenv("MSVC_USE_DEBUG_RUNTIME"));
100 if (pDebugRuntime
&& !strcmp(pDebugRuntime
, "TRUE"))
101 args
.append(" -MDd");
105 args
.append(" -Ob1 -Oxs -Oy-");
107 std::string linkargs
;
108 bool block_linkargs
= false;
110 // Instead of using synced PDB access (-FS), use individual PDB files based on output.
111 // In fact, simply use -Z7, which doesn't use PDB files at all and writes all debug into the .obj file.
112 const char *const pEnvIndividualPDBs(getenv("MSVC_USE_INDIVIDUAL_PDBS"));
113 const bool bIndividualPDBs
= (pEnvIndividualPDBs
&& !strcmp(pEnvIndividualPDBs
, "TRUE"));
114 const char *const pEnvEnableZ7Debug(getenv("ENABLE_Z7_DEBUG"));
115 const bool bEnableZ7Debug
= (pEnvEnableZ7Debug
&& !strcmp(pEnvEnableZ7Debug
, "TRUE")) || bIndividualPDBs
;
117 for(std::vector
<std::string
>::const_iterator i
= rawargs
.begin(); i
!= rawargs
.end(); ++i
) {
118 if (env_prefix_next_arg
)
121 env_prefix_next_arg
= false;
127 // TODO: handle more than just exe output
129 size_t dot
=(*i
).find_last_of(".");
130 if(!(*i
).compare(dot
+1,3,"obj") || !(*i
).compare(dot
+1,1,"o"))
135 else if(!(*i
).compare(dot
+1,3,"exe"))
140 else if(!(*i
).compare(dot
+1,3,"dll"))
141 { // apparently cl.exe has no flag for dll?
142 linkargs
.append(" -dll -out:");
145 else if (dot
== std::string::npos
)
148 args
.append(*i
+ ".exe");
152 std::cerr
<< "unknown -o argument - please adapt gcc-wrapper for \""
153 << (*i
) << "\"" << std::endl
;
157 else if(*i
== "-g" || !(*i
).compare(0,5,"-ggdb")) {
165 // ccache doesn't work with -Zi, the -link -debug for linking will create a final PDB
169 else if(!(*i
).compare(0,2,"-D")) {
170 // need to re-escape strings for preprocessor
171 std::string str
= *i
;
172 for(size_t pos
=str
.find("\""); pos
!=std::string::npos
; pos
=str
.find("\"",pos
)) {
173 str
.replace(pos
,0,"\\");
178 else if(!(*i
).compare(0,2,"-L")) {
179 linkargs
.append(" -LIBPATH:"+(*i
).substr(2));
181 else if(!(*i
).compare(0,2,"-l") && (*i
).compare(0,5,"-link")) {
182 linkargs
.append(" "+(*i
).substr(2)+".lib");
184 else if(!(*i
).compare(0,5,"-def:") || !(*i
).compare(0,5,"/def:")) {
185 // why are we invoked with /def:? cl.exe should handle plain
186 // "foo.def" by itself
187 linkargs
.append(" " + *i
);
189 else if(!(*i
).compare(0,12,"-fvisibility") || *i
== "-fPIC") {
190 //TODO: drop other gcc-specific options
192 else if(!(*i
).compare(0,4,"-Wl,")) {
193 //TODO: drop other gcc-specific options
195 else if(*i
== "-c") {
197 // If -c is specified, there will be no linking anyway,
198 // and passing -link with -c stops ccache from caching.
199 block_linkargs
= true;
201 else if(*i
== "-Werror")
203 else if (*i
== "--wrapper-print-cmdline")
207 size_t pos
= i
->find("=");
208 if (0 == i
->compare(0, pos
, "--wrapper-env-prefix"))
210 if (pos
== std::string::npos
)
211 env_prefix_next_arg
= true;
212 else if (pos
+ 1 == i
->length())
214 // bailout - missing arg
215 env_prefix_next_arg
= true;
219 env_prefix
= i
->substr(pos
+ 1);
226 if (env_prefix_next_arg
)
228 std::cerr
<< "wrapper-env-prefix needs an argument!" << std::endl
;
232 if(!block_linkargs
) {
233 // apparently these must be at the end
234 // otherwise configure tests may fail
235 // note: always use -debug so a PDB file is created
236 args
.append(" -link -debug ");
237 args
.append(linkargs
);
243 int startprocess(std::string command
, std::string args
, bool verbose
)
246 PROCESS_INFORMATION pi
;
247 SECURITY_ATTRIBUTES sa
;
249 HANDLE childout_read
;
250 HANDLE childout_write
;
252 memset(&sa
,0,sizeof(sa
));
253 memset(&si
,0,sizeof(si
));
254 memset(&pi
,0,sizeof(pi
));
256 sa
.nLength
=sizeof(sa
);
257 sa
.bInheritHandle
=TRUE
;
259 if(!CreatePipe(&childout_read
,&childout_write
,&sa
,0)) {
260 std::cerr
<< "Error: could not create stdout pipe" << std::endl
;
265 si
.dwFlags
|= STARTF_USESTDHANDLES
;
266 si
.hStdOutput
=childout_write
;
267 si
.hStdError
=childout_write
;
270 size_t pos
=command
.find("ccache ");
271 size_t len
= strlen("ccache ");
272 if(pos
== std::string::npos
) {
273 pos
=command
.find("ccache.exe ");
274 len
= strlen("ccache.exe ");
276 if(pos
!= std::string::npos
) {
277 args
.insert(0,command
.substr(pos
+len
));
278 command
=command
.substr(0,pos
+len
-1);
281 auto cmdline
= "\"" + command
+ "\" " + args
;
284 std::cerr
<< "CMD= " << command
<< " " << args
<< std::endl
;
286 // Commandline may be modified by CreateProcess
287 char* cmdlineBuf
=_strdup(cmdline
.c_str());
289 if(!CreateProcess(nullptr, // Process Name
290 cmdlineBuf
, // Command Line
291 nullptr, // Process Handle not Inheritable
292 nullptr, // Thread Handle not Inheritable
293 TRUE
, // Handles are Inherited
294 0, // No creation flags
295 nullptr, // Environment for process
296 nullptr, // Use same starting directory
298 &pi
) // Process Information
300 auto const e
= GetLastError();
301 std::cerr
<< "Error: could not create process \"" << cmdlineBuf
<< "\": " << e
<< std::endl
;
305 // if you don't close this the process will hang
306 CloseHandle(childout_write
);
308 // Get Process output
310 DWORD readlen
, writelen
, ret
;
311 HANDLE stdout_handle
=GetStdHandle(STD_OUTPUT_HANDLE
);
313 int success
=ReadFile(childout_read
,buffer
,BUFLEN
,&readlen
,nullptr);
314 // check if the child process has exited
315 if(GetLastError()==ERROR_BROKEN_PIPE
)
318 std::cerr
<< "Error: could not read from subprocess stdout" << std::endl
;
322 WriteFile(stdout_handle
,buffer
,readlen
,&writelen
,nullptr);
325 WaitForSingleObject(pi
.hProcess
, INFINITE
);
326 GetExitCodeProcess(pi
.hProcess
, &ret
);
327 CloseHandle(pi
.hThread
);
328 CloseHandle(pi
.hProcess
);
332 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */