15knots / cmake4eclipse

Let Eclipse use CMake to generate the buildscripts for Eclipse CDT
Eclipse Public License 2.0
85 stars 25 forks source link

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

Open kutschkem opened 6 years ago

kutschkem commented 6 years ago

This is a...

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:

  1. (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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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

15knots commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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 https://github.com/15knots/cmake4eclipse/issues/91#issuecomment-429532799. .

kutschkem commented 6 years ago

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 commented 6 years ago

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

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 commented 6 years ago

OK that is simpler, I will try that.

kutschkem commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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

kutschkem commented 6 years ago

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 commented 6 years ago

Reply to https://github.com/15knots/cmake4eclipse/issues/91#issuecomment-435373963

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 commented 6 years ago

Reply to https://github.com/15knots/cmake4eclipse/issues/91#issuecomment-435443044:

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

15knots commented 6 years ago

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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago
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 commented 5 years ago

My plugin does not do the quote-escaping, it just passes the arguments cmd, /c andenvars.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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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

kutschkem commented 5 years ago

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 commented 5 years ago

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

kutschkem commented 5 years ago

The same array as above also works with Runtime.exec

15knots commented 5 years ago

But that is exactly what one of the previous versions did: Enclose any argument with spaces in double quotes.

kutschkem commented 5 years ago

I'll see if I can find that version and debug what went wrong.

15knots commented 5 years ago

Staged cmake4eclipse-1.12.3-SNAPSHOT.zip at https://drive.google.com/drive/folders/0B-QU1Qnto3huZUZ0QUdxM01pR0U This version will print the arguments to the cmake-console using Arrays.toString(String[] args). Look there for #### Arrays.toString(String[] args)...

15knots commented 5 years ago

Code is now on published on branch issue91, so you can try it. The relevant code is in de.marw.cdt.cmake.core.internal.BuildscriptGenerator#wrapArgsForEnvScript(List)

asterkrans commented 5 years ago

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 commented 5 years ago

@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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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

kutschkem commented 5 years ago

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 commented 5 years ago

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

kutschkem commented 5 years ago

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 commented 5 years ago

    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 commented 5 years ago

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 commented 5 years ago

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

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

15knots commented 5 years ago

@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 commented 5 years ago

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

15knots commented 5 years ago

@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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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

15knots commented 5 years ago

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