Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide way to pass env-vars from bat-file to cmake process (for nmake) #91

Open
2 tasks done
kutschkem opened this issue Oct 11, 2018 · 57 comments
Open
2 tasks done

Comments

@kutschkem
Copy link

This is a...

  • Bug Report
  • Enhancement Request

Brief Description

For my nmake to work, I had to make sure to call vcvars32.bat before cmake. However I found no way to do this other than writing a wrapper batch script around cmake.

(If Bug Report) Brief Summary

What I tried:

  1. Prepending the call to the build command in Preferences -> C/C++ Build -> Builder settings. This did not work as the command is not used for the cmake call.
  2. Using it as pre-build step in Preferences -> C/C++ Build -> Settings -> Build steps. This did not lead to the batch file being called before cmake.
  3. Prepend the call to Preferences -> C/C++ Build -> CMake -> OS Host override -> Windows -> CMake Executable. Didn't work because the entry is parsed as one command instead of allowing arbitrary shell script statements.

In the end I wrote a batch script that called vcvars32 and then passed the arguments to cmake, and used that as cmake executable.

What is the expected behavior?

One of the methods above should have allowed to call the script before cmake is executed to populate environment variables - or another method should exist that allows this.

What behavior are you observing?

cmake seems to be the first thing to be called in the build and no way exists to define a "pre-cmake" step.

Provide the steps to reproduce the issue, if applicable:

(If Enhancement Request) Describe it.

Add a "pre-cmake" step.

Useful Information

cmake4eclipse verssion: 1.10.3
Which OS do you use: Windows 7
Cmake version: 3.10.0

@15knots
Copy link
Owner

15knots commented Oct 11, 2018

Calling vcvars32.bat from Eclipse won't help, a sub-process cannot set environment variables for its parent process (Eclipse in this case).
You will have to stay with your existing cmake-wrapper or write a similar wrapper which start Eclipse.

@15knots
Copy link
Owner

15knots commented Oct 13, 2018

One possible solution could be to call cmake in a sub-shell, and run vcvars32.bat in the same shell before.
But that might fail when cmake is called from the makefile once a CMakeLists.txt was changed.

@kutschkem
Copy link
Author

Shouldn't 3. work if the commands were not passed to the shell in one string but split?

@15knots
Copy link
Owner

15knots commented Oct 16, 2018

Splitting the string at whitespaces? Then nobody will be able to add a path to cmake with white spaces, e.g c:\program files\cmake\...

@kutschkem
Copy link
Author

Using a tokenizer should work, but that would mean "just" putting in a path with whitespaces wouldn't work anymore, they would have to be surrounded by quotation marks. (java.io.StreamTokenizer should work, I think)

@15knots
Copy link
Owner

15knots commented Oct 21, 2018

The path-to-cmake should just hold what its label suggests, adding some token parsing would just confuse useres.

But I could think of an extra option 'run with environment script' which could allow to run a single batch file in the same shell prior to cmake.

@15knots
Copy link
Owner

15knots commented Oct 28, 2018

What is your experience with your wrapper script that calls vcvars32 prior to cmake?
Does it work when cmake is called from the makefile? You will need to edit a CMakeLists.txt and run a build to provoke that.

If that does not cause any issues, I could implement the solution proposed in #91 (comment).
.

@kutschkem
Copy link
Author

I understand the question to be:

  1. generate NMake Makefile with the wrapper script
  2. build using nmake, not by calling cmake --build with the script
  3. check that 2. is succesful

I will test that as soon as possible and let you know the results. My hope would be that all necessary information from the vcvars finds its way in the Makefile, but that needs to be tested for sure.

@15knots
Copy link
Owner

15knots commented Oct 29, 2018

No, even simpler: With your wrapper script in place,

  • run the build once to let the wrapper script generate the makefiles (but you did that already)
  • edit one of your cmakelists.txt and run the build again.

The second build should trigger some makefile rules that invoke cmake from nmake in order to re-generate the makefiles (at least, this is the case with unix makefiles). The cmake process in this case is run without your wrapper script and does not have the environment vars that come from vcvars32. If cmake runs without errors here, we're fine.

@kutschkem
Copy link
Author

OK that is simpler, I will try that.

@kutschkem
Copy link
Author

No it does not work. I tested this by explicitly setting an environment variable in the wrapper script and reading it in the CMakeLists.txt. The first run picks up the variable, the second one does not.

@15knots
Copy link
Owner

15knots commented Oct 31, 2018

Of course it will not work if you explicitly require a new env-var. But that is a different use case.
Does it work if you, for example, add an add_exxecutable()?

@kutschkem
Copy link
Author

Next test, I did:

  1. build with wrapper script in place
  2. change CMakeLists.txt to trigger cmake to run
  3. build again - works as expected
  4. change cmake executable to use the system one - builds as in 3.
  5. remove CMakeCache.txt to trigger cmake to run again - build is unsuccessful

The issue, I think, is that what is not working is the compiler test - it tries to link against libs from the Windows SDK when trying to compile its "simple program", and only afterwards sets the necessary variables to do what the build takes. I think my environment variable test shows that the build can't be depending on the environment variables, somewhere cmake is setting the include paths.

Another test I did was setting the INCLUDE and LIB environment variables to the necessary directories for the Windows SDK - the build without the wrapper script worked fine. So somewhere CMake is keeping the IncludeDirectories and Libpath directories, the rest of the environment doesn't seem to matter. I do not know where it is that this information is kept.

@kutschkem
Copy link
Author

By the way, when I change the cmake command, it does not force a cmake rerun, I think that is probably a bug.

@kutschkem
Copy link
Author

I think I fixed my problem, but it is debatable how nice it is. I call the script and read out the environment variables it sets.

For INCLUDE:

execute_process(COMMAND $ENV{VS140COMNTOOLS}/VsDevCmd.bat && set include OUTPUT_VARIABLE WINDOWSSDK_INCLUDE_DIRS)
string(REPLACE "\\" "/" WINDOWSSDK_INCLUDE_DIRS "${WINDOWSSDK_INCLUDE_DIRS}")
string(REPLACE "INCLUDE=" "" WINDOWSSDK_INCLUDE_DIRS "${WINDOWSSDK_INCLUDE_DIRS}")
message(STATUS "Found the following VS140 include directories: ${WINDOWSSDK_INCLUDE_DIRS}")

And then the same for LIB. I put this all in a find_package script and then use it like any other library. Not really nice, but better than a wrapper script in my opinion.

@15knots
Copy link
Owner

15knots commented Nov 2, 2018

Reply to #91 (comment)

Next test, I did:
1. build with wrapper script in place
2. change CMakeLists.txt to trigger cmake to run
3. build again - works as expected

Fine! This is the prerequisite of the fix of this issue..

4. change cmake executable to use the system one - builds as in 3.
5. remove CMakeCache.txt to trigger cmake to run again - build is unsuccessful

Step 5 is the same as the initial case with freshly checked out sources and no build directory.
This case is going to be addressed by my proposed fix: Running cmake in a sub-shell, and run vcvars32.bat in the same shell before.

BTW, cmake stores the path to the compiler and linker in CMakeCache.txt and the header and library search path in the generated makefiles.

@15knots
Copy link
Owner

15knots commented Nov 2, 2018

Reply to #91 (comment):

With the proposed fix, you won't need that kind of CMakeLists.txt massaging.

@15knots 15knots self-assigned this Nov 2, 2018
@15knots 15knots added this to the next release milestone Nov 2, 2018
@15knots
Copy link
Owner

15knots commented Nov 5, 2018

Could you please try staged version 1.12.3
from https://drive.google.com/open?id=1PHVnRK_ovsExdKlhnjVL3aCAfkWlL_XI ?
It is a zipped p2 update site.

@kutschkem
Copy link
Author

kutschkem commented Nov 12, 2018

It does not work, and I think it is because of the command line you generate:

cmd.exe /c "C:\\LegacyApp\\VisualStudio2015\\Common7\\Tools\\VsDevCmd.bat" && cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON -G "\"NMake Makefiles\"" "\"-DCMAKE_MODULE_PATH:PATH=C:\\Program Files\\eCAL\\cmake\"" -DCMAKE_BUILD_TYPE:STRING=Release -DOFFLINE:STRING=ON -DCMAKE_C_COMPILER_FORCED:STRING=1 -DCMAKE_CXX_COMPILER_FORCED:STRING=1 "C:\\Users\\<user name>\\runtime-xcit-rcp.product\\test_yaaf\\projects\\build\\autogen"

I think this creates a CMD subprocess and then a cmake subprocess, when what you wanted to achieve was the cmake subprocess INSIDE the cmd subprocess. What I think it should look like (enclosing double quotation marks):

cmd.exe /c ""C:\\LegacyApp\\VisualStudio2015\\Common7\\Tools\\VsDevCmd.bat" && cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON -G "\"NMake Makefiles\"" "\"-DCMAKE_MODULE_PATH:PATH=C:\\Program Files\\eCAL\\cmake\"" -DCMAKE_BUILD_TYPE:STRING=Release -DOFFLINE:STRING=ON -DCMAKE_C_COMPILER_FORCED:STRING=1 -DCMAKE_CXX_COMPILER_FORCED:STRING=1 "C:\\Users\\<user name>\\runtime-xcit-rcp.product\\test_yaaf\\projects\\build\\autogen""

See https://stackoverflow.com/a/12892791/1319284

@15knots
Copy link
Owner

15knots commented Nov 13, 2018

Staged a new version that put everything after the /C in a single argument.
https://drive.google.com/open?id=1PHVnRK_ovsExdKlhnjVL3aCAfkWlL_XI

Please test!

@kutschkem
Copy link
Author

kutschkem commented Nov 14, 2018

cmd.exe /c "C:\\LegacyApp\\VisualStudio2015\\Common7\\Tools\\VsDevCmd.bat && cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON -G \"NMake Makefiles\" \"-DCMAKE_MODULE_PATH:PATH=C:\\Program Files\\eCAL\\cmake\" -DCMAKE_BUILD_TYPE:STRING=Release -DOFFLINE:STRING=ON -DCMAKE_C_COMPILER_FORCED:STRING=1 -DCMAKE_CXX_COMPILER_FORCED:STRING=1 C:\\Users\\uidj1662\\runtime-xcit-rcp.product\\test_yaaf\\projects\\build\\autogen && exit %%ERRORLEVEL%%" 
CMake Error: Could not create named generator "NMake

Generators
  Visual Studio 15 2017 [arch] = Generates Visual Studio 2017 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 14 2015 [arch] = Generates Visual Studio 2015 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 12 2013 [arch] = Generates Visual Studio 2013 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 11 2012 [arch] = Generates Visual Studio 2012 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 10 2010 [arch] = Generates Visual Studio 2010 project files.
                                 Optional [arch] can be "Win64" or "IA64".
  Visual Studio 9 2008 [arch]  = Generates Visual Studio 2008 project files.
                                 Optional [arch] can be "Win64" or "IA64".
  Visual Studio 8 2005 [arch]  = Deprecated.  Generates Visual Studio 2005
                                 project files.  Optional [arch] can be
                                 "Win64".
  Borland Makefiles            = Generates Borland makefiles.
  NMake Makefiles              = Generates NMake makefiles.
  NMake Makefiles JOM          = Generates JOM makefiles.
  Green Hills MULTI            = Generates Green Hills MULTI files
                                 (experimental, work-in-progress).
  MSYS Makefiles               = Generates MSYS makefiles.
  MinGW Makefiles              = Generates a make file for use with
                                 mingw32-make.
  Unix Makefiles               = Generates standard UNIX makefiles.
  Ninja                        = Generates build.ninja files.
  Watcom WMake                 = Generates Watcom WMake makefiles.
  CodeBlocks - MinGW Makefiles = Generates CodeBlocks project files.
  CodeBlocks - NMake Makefiles = Generates CodeBlocks project files.
  CodeBlocks - NMake Makefiles JOM
                               = Generates CodeBlocks project files.
  CodeBlocks - Ninja           = Generates CodeBlocks project files.
  CodeBlocks - Unix Makefiles  = Generates CodeBlocks project files.
  CodeLite - MinGW Makefiles   = Generates CodeLite project files.
  CodeLite - NMake Makefiles   = Generates CodeLite project files.
  CodeLite - Ninja             = Generates CodeLite project files.
  CodeLite - Unix Makefiles    = Generates CodeLite project files.
  Sublime Text 2 - MinGW Makefiles
                               = Generates Sublime Text 2 project files.
  Sublime Text 2 - NMake Makefiles
                               = Generates Sublime Text 2 project files.
  Sublime Text 2 - Ninja       = Generates Sublime Text 2 project files.
  Sublime Text 2 - Unix Makefiles
                               = Generates Sublime Text 2 project files.
  Kate - MinGW Makefiles       = Generates Kate project files.
  Kate - NMake Makefiles       = Generates Kate project files.
  Kate - Ninja                 = Generates Kate project files.
  Kate - Unix Makefiles        = Generates Kate project files.
  Eclipse CDT4 - NMake Makefiles
                               = Generates Eclipse CDT 4.0 project files.
  Eclipse CDT4 - MinGW Makefiles
                               = Generates Eclipse CDT 4.0 project files.
  Eclipse CDT4 - Ninja         = Generates Eclipse CDT 4.0 project files.
  Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files.

Buildfile generation error occurred..
cmd.exe exited with status 1. See CDT global build console for details.
Build stopped..

I think you don't need to escape the quotes inside, it looks for the first and last quotes automatically, I think. See https://ss64.com/nt/cmd.html

/S Strip " quote characters from command.
If command starts with a quote, the first and last quote chars in command
will be removed, whether /s is specified or not.

Spaces in Program Path + parameters with spaces:
CMD /k ""c:\batch files\demo.cmd" "Parameter 1 with space" "Parameter2 with space""

@15knots
Copy link
Owner

15knots commented Nov 14, 2018

My plugin does not do the quote-escaping, it just passes the arguments cmd, /c and envars.bat && cmake "-G NMake Makefiles" ... to an instance of ICommandLauncher.
All that quoting happens somewhere in the windows-implementation of Javas Runtime.exec(String[] args) or in Spawner.exec0( String[] cmdarray, String[] envp, String dir, int[] chan). The latter is implemented as windows-specific native C-code.
With all that unknown quoting and cmd.exes unknown/confusing un-quoting, someone with access to a windows machine should help here.

Anyway, I'll give it a last blind try. Staged a new version.
https://drive.google.com/open?id=1PHVnRK_ovsExdKlhnjVL3aCAfkWlL_XI

@kutschkem
Copy link
Author

OK, I'll test and if it doesn't work I can see if I can make time to work on it. Which branch is it in?

@15knots
Copy link
Owner

15knots commented Nov 14, 2018

It is not checked in currently.
If you want to do work on it, start using Runtime.exec(String[] cmdline) and figure the out the cmdline-array to call cmd.exe and run two commands (envars.bat and cmake) which may have spaces in theire command name and spaces in their arguments.
Then hope the Spawner does the same quoting as Runtime.exec() :-)

@kutschkem
Copy link
Author

OK will do. I assume I can somehow trick it with single quotes.

@kutschkem
Copy link
Author

This works for me:

package test_cmake4eclipse;

import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;

public class Main {

  public static void main(String[] args) throws IOException, InterruptedException {
    String[] cmdarray = new String[] {"cmd.exe", "/c", "C:\\LegacyApp\\VisualStudio2015\\Common7\\Tools\\VsDevCmd.bat && cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON -G \"NMake Makefiles\" \"-DCMAKE_MODULE_PATH:PATH=C:\\Program Files\\eCAL\\cmake\" -DCMAKE_BUILD_TYPE:STRING=Release -DOFFLINE:STRING=ON -DCMAKE_C_COMPILER_FORCED:STRING=1 -DCMAKE_CXX_COMPILER_FORCED:STRING=1 C:\\Users\\uidj1662\\runtime-xcit-rcp.product\\test_yaaf\\projects\\build\\autogen && exit %%ERRORLEVEL%%"};
    ProcessBuilder bldr = new ProcessBuilder(cmdarray);
    bldr.redirectOutput(Redirect.INHERIT);
    bldr.redirectError(Redirect.INHERIT);
    Process pr = bldr.start();
    pr.waitFor();

  }

}

@kutschkem
Copy link
Author

Tested the last staged version, didn't work, with similar error message as before.

@asterkrans
Copy link

I don't know what your vcvars32.bat do, but I set up my environment before starting eclipse. Would it be possible for you as well to setup your environment before starting eclipse?

@kutschkem
Copy link
Author

@asterkrans Of course that works, but is not really convenient for my users. Unless there is a way to provide a wrapper script with the product?

@15knots
Copy link
Owner

15knots commented Dec 7, 2018

Could someone please test staged cmake4eclipse-1.12.3-SNAPSHOT.zip at https://drive.google.com/drive/folders/0B-QU1Qnto3huZUZ0QUdxM01pR0U on windows so we can proceed here?
This version will print the arguments to the cmake-console using Arrays.toString(String[] args). Look there for #### Arrays.toString(String[] args)...

@kutschkem
Copy link
Author

Testing the issue91 branch right now, this still have problems with the escaping or something, since I now have the code in my IDE, I'll see if I can fix it.

#### Arrays.toString(String[] args)=[cmd.exe, /c, C:\LegacyApp\VisualStudio2015\Common7\Tools\VsDevCmd.bat & cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON -G "NMake Makefiles" C:\Users\uidj1662\runtime-xcit-rcp.product\test_yaaf\projects\testsProto\build\autogen]cmd.exe /c "C:\\LegacyApp\\VisualStudio2015\\Common7\\Tools\\VsDevCmd.bat & cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON -G \"NMake Makefiles\" C:\\Users\\uidj1662\\runtime-xcit-rcp.product\\test_yaaf\\projects\\testsProto\\build\\autogen" 
CMake Error: Could not create named generator "NMake

Generators
  Visual Studio 15 2017 [arch] = Generates Visual Studio 2017 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 14 2015 [arch] = Generates Visual Studio 2015 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 12 2013 [arch] = Generates Visual Studio 2013 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 11 2012 [arch] = Generates Visual Studio 2012 project files.
                                 Optional [arch] can be "Win64" or "ARM".
  Visual Studio 10 2010 [arch] = Generates Visual Studio 2010 project files.
                                 Optional [arch] can be "Win64" or "IA64".
  Visual Studio 9 2008 [arch]  = Generates Visual Studio 2008 project files.
                                 Optional [arch] can be "Win64" or "IA64".
  Visual Studio 8 2005 [arch]  = Deprecated.  Generates Visual Studio 2005
                                 project files.  Optional [arch] can be
                                 "Win64".
  Borland Makefiles            = Generates Borland makefiles.
  NMake Makefiles              = Generates NMake makefiles.
  NMake Makefiles JOM          = Generates JOM makefiles.
  Green Hills MULTI            = Generates Green Hills MULTI files
                                 (experimental, work-in-progress).
  MSYS Makefiles               = Generates MSYS makefiles.
  MinGW Makefiles              = Generates a make file for use with
                                 mingw32-make.
  Unix Makefiles               = Generates standard UNIX makefiles.
  Ninja                        = Generates build.ninja files.
  Watcom WMake                 = Generates Watcom WMake makefiles.
  CodeBlocks - MinGW Makefiles = Generates CodeBlocks project files.
  CodeBlocks - NMake Makefiles = Generates CodeBlocks project files.
  CodeBlocks - NMake Makefiles JOM
                               = Generates CodeBlocks project files.
  CodeBlocks - Ninja           = Generates CodeBlocks project files.
  CodeBlocks - Unix Makefiles  = Generates CodeBlocks project files.
  CodeLite - MinGW Makefiles   = Generates CodeLite project files.
  CodeLite - NMake Makefiles   = Generates CodeLite project files.
  CodeLite - Ninja             = Generates CodeLite project files.
  CodeLite - Unix Makefiles    = Generates CodeLite project files.
  Sublime Text 2 - MinGW Makefiles
                               = Generates Sublime Text 2 project files.
  Sublime Text 2 - NMake Makefiles
                               = Generates Sublime Text 2 project files.
  Sublime Text 2 - Ninja       = Generates Sublime Text 2 project files.
  Sublime Text 2 - Unix Makefiles
                               = Generates Sublime Text 2 project files.
  Kate - MinGW Makefiles       = Generates Kate project files.
  Kate - NMake Makefiles       = Generates Kate project files.
  Kate - Ninja                 = Generates Kate project files.
  Kate - Unix Makefiles        = Generates Kate project files.
  Eclipse CDT4 - NMake Makefiles
                               = Generates Eclipse CDT 4.0 project files.
  Eclipse CDT4 - MinGW Makefiles
                               = Generates Eclipse CDT 4.0 project files.
  Eclipse CDT4 - Ninja         = Generates Eclipse CDT 4.0 project files.
  Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files.

Buildfile generation error occurred..
cmd.exe exited with status 1. See CDT global build console for details.
Build stopped..

@kutschkem
Copy link
Author

WTF the command line looks exactly like in my example, yet it still doesn't work?!

@kutschkem
Copy link
Author

I dug into the code until I ended up at the native portion. This is what cdt does with the command array that we pass to the command launcher:

	// Prepare command line
	for(i = 0; i < nCmdTokens; ++i) 
    	{
		jstring item = (jstring)env->GetObjectArrayElement(cmdarray, i);
		jsize    len = env->GetStringLength(item);
		int nCpyLen;
		const wchar_t *  str = (const wchar_t *)env->GetStringChars(item, 0);	
		if(NULL != str) 
			{
			int requiredSize= nPos+len+2;
			if (requiredSize > 32*1024) {
				ThrowByName(env, "java/io/IOException", "Command line too long");
				return 0;
			}				
			ensureSize(&szCmdLine, &nCmdLineLength, requiredSize);
			if (NULL == szCmdLine) {
				ThrowByName(env, "java/io/IOException", "Not enough memory");
				return 0;
			}
			    
			if(0 > (nCpyLen = copyTo(szCmdLine + nPos, str, len, nCmdLineLength - nPos)))
                {
				ThrowByName(env, "java/io/IOException", "Command line too long");
				return 0;
			}
			nPos += nCpyLen;
			szCmdLine[nPos] = _T(' ');
			++nPos;
			env->ReleaseStringChars(item, (const jchar *)str);
		}
	}
	szCmdLine[nPos] = _T('\0');
//[some stuff ....]

    ret = CreateProcessW(0,                /* executable name */
                        szCmdLine,        /* command line */
                        0,                /* process security attribute */
                        0,                /* thread security attribute */
                        FALSE,            /* inherits system handles */
                        flags,            /* normal attached process */
                        szEnvBlock,		  /* environment block */
                        cwd,              /* change to the new current directory */
                        &si,              /* (in)  startup information */
                        &pi);             /* (out) process information */

And the copyTo method:

int copyTo(wchar_t * target, const wchar_t * source, int cpyLength, int availSpace)
{
	BOOL bSlash = FALSE;
	int i = 0, j = 0;
	int totCpyLength = cpyLength;

#define QUOTATION_DO   0
#define QUOTATION_DONE 1
#define QUOTATION_NONE 2

	int nQuotationMode = 0;



	if(availSpace <= cpyLength) // = to reserve space for final '\0'
		return -1;

	if((_T('\"') == *source) && (_T('\"') == *(source + cpyLength - 1)))
		{
		nQuotationMode = QUOTATION_DONE;
		}
	else
	if(wcschr(source, _T(' ')) == NULL)
		{
		// No reason to quotate term becase it doesn't have embedded spaces
		nQuotationMode = QUOTATION_NONE;
		}
	else
		{
		// Needs to be quotated
		nQuotationMode = QUOTATION_DO;
		*target = _T('\"');
		++j;
		}


	for(; i < cpyLength; ++i, ++j) 
		{
		if(source[i] == _T('\\'))
			bSlash = TRUE;
		else
			{
			// Don't escape embracing quotation marks
			if((source[i] == _T('\"')) && !((nQuotationMode == QUOTATION_DONE) && ((i == 0) || (i == (cpyLength - 1))) ) )
				{
				if(!bSlash) // If still not escaped
					{
					if(j == availSpace)
						return -1;
					target[j] = _T('\\');
					++j;
					}
				}
			bSlash = FALSE;
			}

		if(j == availSpace)
			return -1;
		target[j] = source[i];
		}

	if(nQuotationMode == QUOTATION_DO)
		{
		if(j == availSpace)
			return -1;
		target[j] = _T('\"');
		++j;
		}

	return j;
}

I don't understand why they don't just use the JRE methods for that and need an own implementation...

I think no matter what we do here, the quotation marks will be quoted, when we need them unquoted.

@kutschkem
Copy link
Author

I am trying now to get something to work with powershell.exe -Command" instead. of cmd /c`, maybe that has less funky escape rules.

@kutschkem
Copy link
Author

I tried with this command line but still cmake complains about missing quotations at the Nmake Generator

#### Arrays.toString(String[] args)=[powershell.exe, -Command, CMD /c "C:\LegacyApp\VisualStudio2015\Common7\Tools\VsDevCmd.bat && set", |, .{process{if($_, -match, '^([^=]+)=(.*)'){, Set-Variable, $matches[1], $matches[2], }}}, ;, cmake, -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON, -DCMAKE_RULE_MESSAGES:BOOL=OFF, -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON, -G, NMake Makefiles, C:\Users\uidj1662\runtime-xcit-rcp.product\test_yaaf\projects\testsProto\build\autogen]

@kutschkem
Copy link
Author


	swprintf(szCmdLine, L"\"%sstarter.exe\" %i %i %s %s %s %s %s ", path, pid, nLocalCounter, eventBreakName, eventWaitName, eventTerminateName, eventKillName, eventCtrlcName);
	nPos = wcslen(szCmdLine);

Okay, so ACTUALLY the commandline is prepended with starter.exe which is this code: https://git.eclipse.org/c/cdt/org.eclipse.cdt.git/tree/core/org.eclipse.cdt.core.win32/library/starter/starter.cpp

And here I don't know what is going on, why that code is needed. Do you have any contacts to cdt guys? I think some input on how to tackle this issue would be nice. I don't understand why normally the Quoting works as expected, but as soon as we mess with the command line something breaks.

@asterkrans
Copy link

asterkrans commented Dec 14, 2018

Maybe this can help: "EnableDelayedExpansion is Disabled by default.
EnableDelayedExpansion can also be enabled by starting CMD with the /v switch."

I have not fully understood the issue here, but this was the solution once when I had similar problems.

@asterkrans
Copy link

Sorry, I guess Delayed Expansion that I mentioned above only affects variable expansion.
Maybe ^ escape character?

https://www.robvanderwoude.com/escapechars.php

@15knots
Copy link
Owner

15knots commented Dec 14, 2018

@kutschkem

Arrays.toString(String[] args)=[cmd.exe, /c, C:\LegacyApp\VisualStudio2015\Common7\Tools\VsDevCmd.bat & cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON -G "NMake Makefiles" C:\Users\uidj1662\runtime-xcit-rcp.product\test_yaaf\projects\testsProto\build\autogen]

should at least work with Runtime.exec().

starter.exe is intended to kill its complete sub-process tree if it is terminated.
Think of starter.exe invoking make: If you use java's Runitme.exec() to invoke make on windows and then call Process.destroy(), only the make process will be terminated, but none of its sub-processes.

Two things I note here:

  1. If just cmake is invoked, starter.cpp handles the quoting of arguments with spaces properly.
  2. If cmd is invoked, starter.cpp fails to handle the quoting of arguments with spaces properly.

So the question is how to get the command args in cmake4eclipse right in order to pass quoted args down through starter.exe and cmd.exe to cmake.exe.

To get an answer, you could try to

  1. Add a sleep command to VsDevCmd.bat and examine the command-lines in the process tree. Both for 1. and 2. above. (BTW: ping on windows makes an equivalent for sleep on linux.)
  2. Open cmd.exe and fiddle aroung with starter.exe until you get a working command-line for this issue.

Then pray to figure out a working counter-quoting algorithm to make commands args to pass properly through ICommandLauncher.execute(args), launcher.exe, cmd.exe to cmake.exe.
EDIT: If you can't figure out an algorithm, we could implement a preformance-degrading, space-wasting solution: Write a batch file to %TEMP% with the commands for VsDevCmd.bat and cmake and call that.

@15knots
Copy link
Owner

15knots commented Dec 14, 2018

@asterkrans %sstarter.exe? You mix printf(1) format specifiers with cmd.exe environment variable specifiers here.

@15knots
Copy link
Owner

15knots commented Jan 4, 2019

@kutschkem Maybe it is sufficient to just add the file system location of the VS compilers and linkers to %PATH% when cmake is invoked instead of running vcvars32.bad.
See solution for MinGW at https://github.com/15knots/cmake4eclipse/blob/master/de.marw.cdt.cmake.core/doc/html/t_MinGW_setup.html

Could you give that a try and report back?

@kutschkem
Copy link
Author

I have manually edited the environment variables before, and in my case needed to adapt INCLUDE and LIB (the necessary programs I had already added to PATH)

@15knots
Copy link
Owner

15knots commented Jan 7, 2019

I have manually edited the environment variables before, and in my case needed to adapt INCLUDE and LIB (the necessary programs I had already added to PATH)

Ah, OK.

Looking at the code of starter.cpp, it seems to escape double quotes by a backslash, which is not something cmd.exe undestands (If i read the docs correctly).

So the only option would be to write the commands to a batch file and let cmd.exe execute that.
But this has a draw-back: The actuall command line for cmake is no longer visible in the console.

@15knots
Copy link
Owner

15knots commented Jan 10, 2019

@kutschkem Could you try with the latest commits on the issue91 branch? It uses a batch file.

@15knots
Copy link
Owner

15knots commented Feb 1, 2019

Bump @kutschkem: Could you please test? I would like to incorporate the fix among others into the next release.

15knots added a commit that referenced this issue Feb 2, 2019
15knots added a commit that referenced this issue Feb 2, 2019
@kutschkem
Copy link
Author

I tested this again,
there is one small issue, other than that it works as expected:

You generate:

"C:\LegacyApp\VisualStudio2015\Common7\Tools\VsDevCmd.bat" || exit /b
cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON -G "NMake Makefiles" C:\Users\uidj1662\runtime-xcit-rcp.product\test_yaaf\projects\testsProto\build\autogen || exit /b

The || exit /b construct didn't work for me, so I replaced it with

"C:\LegacyApp\VisualStudio2015\Common7\Tools\VsDevCmd.bat" && cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON -G "NMake Makefiles" C:\Users\uidj1662\runtime-xcit-rcp.product\test_yaaf\projects\testsProto\build\autogen

That works but I have not tested what happens when the script fails with an error code.

@15knots
Copy link
Owner

15knots commented Feb 4, 2019

Thank you for testing.
The || exit /b is intended to exit cmd.exe and return an error code to Eclipse.
Could you try with || exit %errorlevel%? To cause an error, you could pass a non-existing batch file name.

@kutschkem
Copy link
Author

The issue I had was that the exit was happening although the script returned an errorlevel 0

@15knots
Copy link
Owner

15knots commented Feb 13, 2019

Could you test the new commit?
It invokes the temporary bat file without calling cmd.exe and should produce a bat file like

call VsDevCmd.bat && cmake -G ...
exit /b %errorlevel%

The script

  • must abort on the first command that terminates with an exit-code != 0 (aka errorlevel) and pass that exit-code to cmake4eclipse
  • must pass exit-code == 0 iff both VsDevCmd.bat and cmake terminate without error

If the generated script does not, it's up to a person with a windows machine (you) to fix that since I have linux.

@kutschkem
Copy link
Author

Findings:

  1. Using the VsDevCmd.bat sets the environment variables for cmake as expected
  2. When the script fails, cmake is not called (as is correct), but the build triggers nmake regardless, which in turn just calls cmake without the script

@15knots
Copy link
Owner

15knots commented Feb 18, 2019

When the script fails, cmake is not called (as is correct), but the build triggers nmake regardless, which in turn just calls cmake without the script

Did you make VsDevCmd.bat fail or did you specify a non-existing path to the VsDevCmd.bat?

If %errorlevel% indicates a failure, you should see a message like
exited with status 1. See CDT global build console for details.
in the cmake console.

@kutschkem
Copy link
Author

I tested the "failing script" with a script that just read exit /b 42. I haven't tested a non-existing path.

@15knots 15knots changed the title Provide way to call pre-build commands Provide way to pass env-vars from bat-file to cmake process (for nmake) Apr 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants