0

We are struggling with a failed CMake build on MinGW and MinGW-64. Our project is a C++ library. Our CMakeLists.txt has a block like below. The block identifies the target platform through the compiler (other methods are too unreliable, especially on ARM, MIPS and PPC):

set(SHELL_CMD sh -c)
set(GREP_CMD egrep -i -c)

execute_process(COMMAND ${SHELL_CMD} "${CMAKE_CXX_COMPILER} -dumpmachine 2>&1"
    COMMAND ${GREP_CMD} "amd64"
    OUTPUT_VARIABLE CRYPTOPP_AMD64
    OUTPUT_STRIP_TRAILING_WHITESPACE)

...

# http://github.com/weidai11/cryptopp/issues/466
execute_process(COMMAND ${SHELL_CMD} "${CMAKE_CXX_COMPILER} -dumpmachine 2>&1"
    COMMAND ${GREP_CMD} "mingw32"
    OUTPUT_VARIABLE CRYPTOPP_MINGW32
    OUTPUT_STRIP_TRAILING_WHITESPACE)

# http://github.com/weidai11/cryptopp/issues/466
execute_process(COMMAND ${SHELL_CMD} "${CMAKE_CXX_COMPILER} -dumpmachine 2>&1"
    COMMAND ${GREP_CMD} "w64-mingw32"
    OUTPUT_VARIABLE CRYPTOPP_MINGW64
OUTPUT_STRIP_TRAILING_WHITESPACE)

It succeeds on 9 of 11 platforms, but fails for MinGW and MinGW-64. From our bug report tracking the issue, the following on MinGW-64:

execute_process(COMMAND ${SHELL_CMD} "${CMAKE_CXX_COMPILER} -dumpmachine 2>&1"
    COMMAND ${GREP_CMD} "w64-mingw32"
    OUTPUT_VARIABLE CRYPTOPP_MINGW64
OUTPUT_STRIP_TRAILING_WHITESPACE)

message(STATUS ${CRYPTOPP_MINGW64})

execute_process(COMMAND ${SHELL_CMD} "${CMAKE_CXX_COMPILER} -dumpmachine 2>&1"
    COMMAND ${GREP_CMD} "mingw32"
    OUTPUT_VARIABLE CRYPTOPP_MINGW32
OUTPUT_STRIP_TRAILING_WHITESPACE)

message(STATUS ${CRYPTOPP_MINGW32})

The statements produce an empty message. Removing OUTPUT_STRIP_TRAILING_WHITESPACE does not affect the issue. And running c++ -dumpmachine | egrep -i -c w64-mingw32 from the MinGW terminal produces expected results.

We found CMAKE_COMPILER_IS_GNUCXX and CMAKE_CXX_COMPILER_ID are empty but it does not seem to apply since the compiler is set in our case. (It is the only other "cmake empty variable mingw" we have found).

Unfortunately, I don't know what version of Cmake is being used. Our bug report includes the CMake output, but CMake fails to print its version numbers.

Why is CMake failing to set the variables CRYPTOPP_MINGW64 and CRYPTOPP_MINGW32 on MinGW and MinGW-64?


Here's a typical output from CMake while configuring.

=== Building cryptopp ===
mkdir -p deps/cryptopp/build/
cd deps/cryptopp/build/ && cmake -G 'MSYS Makefiles' -D CMAKE_BUILD_TYPE=Release -D BUILD_TESTING=OFF -D BUILD_SHARED=OFF -DCMAKE_CXX_FLAGS="-march=native" ../ && make
-- The C compiler identification is GNU 6.2.0
-- The CXX compiler identification is GNU 6.2.0
-- Check for working C compiler: C:/msys32/mingw32/bin/gcc.exe
-- Check for working C compiler: C:/msys32/mingw32/bin/gcc.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/msys32/mingw32/bin/g++.exe
-- Check for working CXX compiler: C:/msys32/mingw32/bin/g++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - found
-- Found Threads: TRUE  
-- Compiler: 
-- Flags: -march=native
-- Build type: Release
-- 
-- The following OPTIONAL packages have been found:

 * Threads

-- Configuring done
CMake Warning (dev) at CMakeLists.txt:503 (add_dependencies):
  Policy CMP0046 is not set: Error on non-existent dependency in
  add_dependencies.  Run "cmake --help-policy CMP0046" for policy details.
  Use the cmake_policy command to set the policy and suppress this warning.

  The dependency target "clean" of target "distclean" does not exist.
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Generating done
-- Build files have been written to: C:/msys32/home/buildbot/slave/kovri-all-win32/build/deps/cryptopp/build
arrowd
  • 33,231
  • 8
  • 79
  • 110
jww
  • 97,681
  • 90
  • 411
  • 885

2 Answers2

2

You need to separate your arguments from the commands.

set(SHELL_CMD sh)
set(SHELL_CMD_ARGS "-c")
set(GREP_CMD egrep)
set(GREP_CMD_ARGS "-i -c")

execute_process(COMMAND ${SHELL_CMD} "${SHELL_CMD_ARGS} ${CMAKE_CXX_COMPILER} -dumpmachine 2>&1"
vre
  • 6,041
  • 1
  • 25
  • 39
  • Thanks @vre. Let me give it a go. Unfortunately, I don't have a MinGW machine for testing, so I have to ask someone else to perform the test. But I can test the change on the other platforms. – jww Aug 25 '17 at 13:04
  • Another question (if you don't mind): should the arguments be quoted separately? I.e., `execute_process(COMMAND "${SHELL_CMD}" "${SHELL_CMD_ARGS}" "${CMAKE_CXX_COMPILER}" "-dumpmachine" "2>&1"`? The CMake documents for [execute_process](https://cmake.org/cmake/help/v3.0/command/execute_process.html) don't explain things very well, and don't offer examples (*q.v.*). – jww Aug 25 '17 at 13:30
  • It appears the documentation problem has existed for years. Here's an example of the problem dating from 2011: [cmake execute_process() always fails with “No such file or directory” when I call git](https://stackoverflow.com/q/6797395/608639). It befuddles me when a project won't fix its documentation. What's the point in allowing users to make the same mistakes over and over again, year after year? – jww Aug 25 '17 at 13:33
  • I don't think it makes a difference. Only the argument after COMMAND needs to name the exact command. – vre Aug 25 '17 at 13:37
  • 1
    We reported the documentation problems on the CMake mailing list: [Please update the documentation for execute_process](https://cmake.org/pipermail/cmake/2017-August/066140.html). Hopefully we will have an answer soon regarding both quoting and commas. – jww Aug 25 '17 at 14:15
  • Thanks again @VRE. So it looks like the changes did not [fix the problem](https://github.com/weidai11/cryptopp/issues/466#issuecomment-325036687). Very frustrating... – jww Aug 25 '17 at 21:36
  • I also thought that would work out. To gain further insight what is malfunctioning I would try to print the output of the execute_process command. e.g. `execute_process(COMMAND ${SHELL_CMD} "${SHELL_CMD_ARGS} ${CMAKE_CXX_COMPILER} -dumpmachine 2>&1" OUTPUT_VARIABLE out_msg ERROR_VARIABLE err_msg ) message(STATUS "${out_msg} ${err_msg}")` I would also add CXX as last argument to the project command. – vre Aug 25 '17 at 23:19
  • Thanks. We tried to add `CXX` to the project but it broke earlier versions of CMake. We had problems on Fedora 15, CentOS 5, OpenBSD 4 and Ubuntu 10. (We support back further than that. We had to compromise some for CMake users). Also see [Tell CMake to use C++ compiler for C files coming from CMake?](https://stackoverflow.com/q/37931068/608639) – jww Aug 25 '17 at 23:39
1

The problem turned out to be use of SHELL_CMD, sh -c and positional arguments. First, SHELL_CMD needed to be sh only. Second, the -c argument needed to follow the command separately. Third, we needed to quote the entire string. Related, see Why doesn't echo called as /bin/sh -c echo foo output anything? on Unix & Linux Stack Exchange.

We don't know where the use of sh like that came from. We're guessing it was cobbled together way back when and the cruft remained until it caused a problem. It probably should have failed on all platforms. We still don't know if 2>&1 is correct. Its unfortunate CMake docs for execute_process are not well explained and offer no examples.

We changed our target machine detection code to the following. The code now quotes the argument to sh to avoid problems with argument passing.

function(DumpMachine output pattern)
  execute_process(
      COMMAND sh -c "${CMAKE_CXX_COMPILER} -dumpmachine 2>&1"
      COMMAND egrep -i -c "${pattern}"
      OUTPUT_VARIABLE ${output}
      OUTPUT_STRIP_TRAILING_WHITESPACE)
  set(${output} "${${output}}" PARENT_SCOPE)
endfunction(DumpMachine)

DumpMachine(CRYPTOPP_AMD64 "amd64|x86_64")
DumpMachine(CRYPTOPP_I386 "i.86")
DumpMachine(CRYPTOPP_MINGW32 "\\<mingw32\\>")
DumpMachine(CRYPTOPP_MINGW64 "w64-mingw32|mingw64")
DumpMachine(CRYPTOPP_X32 "x32")
DumpMachine(CRYPTOPP_AARCH32 "Aarch32")
DumpMachine(CRYPTOPP_AARCH64 "Aarch64")
DumpMachine(CRYPTOPP_ARM "\\<arm\\>|armhf|arm7l")
jww
  • 97,681
  • 90
  • 411
  • 885