I'm trying to learn cmake and do some basic stuff. It's not going well.
This output seems completely bizarre and broken:
-- The C compiler identification is GNU 10.2.0
-- Check for working C compiler: /usr/bin/x86_64-w64-mingw32-gcc.exe
-- Check for working C compiler: /usr/bin/x86_64-w64-mingw32-gcc.exe - works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
PLATFORM_DIR: /home/dtrombley/src/p0/platform/x86_64-pc-cygwin Building on x86_64-pc-cygwin
Including contrib-src/glad...
CMake Error at contrib-src/glad/CMakeLists.txt:19 (project): The CMAKE_C_COMPILER:
x86_64-w64-mingw32-gcc
is not a full path and was not found in the PATH.
Tell CMake where to find the compiler by setting either the environment variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to the compiler, or to the compiler name if it is in the PATH.
-- Configuring incomplete, errors occurred! See also "/home/dtrombley/src/p0/build/CMakeFiles/CMakeOutput.log". See also "/home/<user>/src/p0/build/CMakeFiles/CMakeError.log".
I have a CMakeLists.txt in the top directory of my project, that finds my compiler just fine - as you can see about. The compiler is on the system path:
$ which x86_64-w64-mingw32-gcc
/usr/bin/x86_64-w64-mingw32-gcc
Then I include a subdirectory with add_subdirectory(), and it complains that it can't find the C compiler. Which the parent project has found. Shouldn't CMAKE_C_COMPILER be set and inherited by the child directory?
Why would the parent directory be able to find it, but the child directory cannot?
Additionally, setting the CC environment variable as suggested has zero effect.
What is going on here? Setting CMAKE_C_COMPILER explicitly results in the same output.
Related
Scenario
I'm in the process of debugging a CMake script.
In order to produce usable output for me to inspect, I use the following invocation:
cmake -S . -B build -DENABLE_MODULE_A=OFF -DENABLE_MODULE_B=OFF -DENABLE_MODULE_C=OFF --trace-source=CMakeLists.txt --trace-expand |& grep VARIABLE_IM_INTERESTED_IN > build/testout.utf8
Problem
This approach is sub-par, because I'm really only interested in one variable that is expanded in the CMake script in question. grep-ing for that after running it in trace-mode seems to be quite cumbersome, especially since the variable gets expanded multiple times, however I'm interested only in the last, full expansion of said variable.
Desired result
Ideally, there is a command line option for CMake, to print/expand only the one variable I'm interested in. I can filter for the last occurrence of that variable with external tools (for instance tail), but grepping the entire trace output for just one file, seems excessive. In essence I'm looking for a command line option to inspect an arbitrary variable, instead of tracing the entirety of the CMake script.
It is however, not an option to change the CMakeFiles.txt such that this one variable is printed. That is for external reasons, of which I have no control of.
Use variable_watch and CMAKE_PROJECT_INCLUDE_BEFORE as a debugging tool. Create a file called watch_var.cmake with the following contents:
cmake_minimum_required(VERSION 3.24)
variable_watch("${watch_var}")
Now here's an example project:
cmake_minimum_required(VERSION 3.24)
project(example)
set(VARIABLE_IM_INTERESTED_IN foo)
string(APPEND VARIABLE_IM_INTERESTED_IN " bar")
At the command line:
$ cmake -G Ninja -S . -B build -DCMAKE_PROJECT_INCLUDE_BEFORE=$PWD/watch_var.cmake -Dwatch_var=VARIABLE_IM_INTERESTED_IN
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Debug Log at CMakeLists.txt:4 (set):
Variable "VARIABLE_IM_INTERESTED_IN" was accessed using MODIFIED_ACCESS
with value "foo".
CMake Debug Log at CMakeLists.txt:5 (string):
Variable "VARIABLE_IM_INTERESTED_IN" was accessed using READ_ACCESS with
value "foo".
CMake Debug Log at CMakeLists.txt:5 (string):
Variable "VARIABLE_IM_INTERESTED_IN" was accessed using MODIFIED_ACCESS
with value "foo bar".
-- Configuring done
-- Generating done
-- Build files have been written to: /home/reinking/test2/build
Docs: https://cmake.org/cmake/help/latest/command/variable_watch.html
I haven't been using Clion for some time and these days I tried to run an old project and it gave me this compile error (It used to work fine). Then I created a new project to test, the error still persists. I also tried to update my Clion. Here is the error message:
/Applications/CLion.app/Contents/bin/cmake/mac/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_MAKE_PROGRAM=/Applications/CLion.app/Contents/bin/ninja/mac/ninja -DCMAKE_CXX_COMPILER=/usr/local/Cellar/gcc/9.2.0_1/bin/g++-9 -G Ninja /Users/yzr/Desktop/untitled
-- The C compiler identification is AppleClang 13.0.0.13000029
-- The CXX compiler identification is unknown
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - failed
-- Check for working CXX compiler: /usr/local/Cellar/gcc/9.2.0_1/bin/g++-9
-- Check for working CXX compiler: /usr/local/Cellar/gcc/9.2.0_1/bin/g++-9 - broken
CMake Error at /Applications/CLion.app/Contents/bin/cmake/mac/share/cmake-3.21/Modules/CMakeTestCXXCompiler.cmake:62 (message):
The C++ compiler
"/usr/local/Cellar/gcc/9.2.0_1/bin/g++-9"
is not able to compile a simple test program.
It fails with the following output:
Change Dir: /Users/yzr/Desktop/untitled/cmake-build-debug/CMakeFiles/CMakeTmp
Run Build Command(s):/Applications/CLion.app/Contents/bin/ninja/mac/ninja cmTC_5a895 && [1/2] Building CXX object CMakeFiles/cmTC_5a895.dir/testCXXCompiler.cxx.o
FAILED: CMakeFiles/cmTC_5a895.dir/testCXXCompiler.cxx.o
/usr/local/Cellar/gcc/9.2.0_1/bin/g++-9 -o CMakeFiles/cmTC_5a895.dir/testCXXCompiler.cxx.o -c /Users/yzr/Desktop/untitled/cmake-build-debug/CMakeFiles/CMakeTmp/testCXXCompiler.cxx
dyld: Library not loaded: /usr/local/opt/isl/lib/libisl.21.dylib
Referenced from: /usr/local/Cellar/gcc/9.2.0_1/libexec/gcc/x86_64-apple-darwin18/9.2.0/cc1plus
Reason: image not found
g++-9: internal compiler error: Abort trap: 6 signal terminated program cc1plus
Please submit a full bug report,
with preprocessed source if appropriate.
See <https://github.com/Homebrew/homebrew-core/issues> for instructions.
ninja: build stopped: subcommand failed.
CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
CMakeLists.txt:2 (project)
-- Configuring incomplete, errors occurred!
See also "/Users/yzr/Desktop/untitled/cmake-build-debug/CMakeFiles/CMakeOutput.log".
See also "/Users/yzr/Desktop/untitled/cmake-build-debug/CMakeFiles/CMakeError.log".
Here is how my CMakeList.txt looks like:
cmake_minimum_required(VERSION 3.21)
project(untitled)
set(CMAKE_CXX_STANDARD 14)
add_executable(untitled main.cpp)
I read this post and added the environment variable but it doesn't seem to work. This is really weird, as it all worked fine. It's just I didn't touch it for some time and need to take a look now. Has anyone encountered this before? Thanks!
Maybe you can try to delete the previous generated cmake-build-debug directory. As the outside environment and version may be updated, some information generated in previous cmake-build-debug directory may no longer be useful. So delete it and Reload the make file to see whether the problem could be solved.
Goal
I am using CMake to make the build for my project which is an embedded firmware based on ARM Cortex platform built using arm-none-eabi-gcc-6.3.1 compiler, using VSCode Editor, and on Windows host. I am trying to make a second build for testing on the Windows system I am using for the same project.
The First Solution Problem
The issue I am having is that whenever I need to switch my build from production to test, I have to delete the build files and rerun the CMake command with the test argument, when I do not do that, the build does not change the ARM compiler to the one I intend to use (I am guessing it is a caching problem). I have tried make clean and make rebuild_cache thinking that it may clean the cache and solve the problem for me, and did not work.
A fresh build Example:
Project\build> cmake -G"MinGW Makefiles" -DTARGET_GROUP=test ..
You have changed variables that require your cache to be deleted.
Configure will be re-run and you may have to reset some variables.
The following variables have changed:
CMAKE_C_COMPILER= C:/MinGW/bin/gcc.exe
CMAKE_CXX_COMPILER= C:/MinGW/bin/g++.exe
-- The C compiler identification is GNU 6.3.0
-- The CXX compiler identification is GNU 6.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/MinGW/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/MinGW/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: Path\to\Project\build
Project\build>make
(successful make)
The second build:
Project\build> cmake -G"MinGW Makefiles" -DTARGET_GROUP=production ..
You have changed variables that require your cache to be deleted.
Configure will be re-run and you may have to reset some variables.
The following variables have changed:
CMAKE_C_COMPILER= Path/to/arm-gnu-toolchain/bin/arm-none-eabi-gcc.exe
CMAKE_CXX_COMPILER= Path/to/arm-gnu-toolchain/bin/arm-none-eabi-g++.exe
-- The C compiler identification is GNU 6.3.0
-- The CXX compiler identification is GNU 6.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/MinGW/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/MinGW/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: Path\to\Project\build
Project\build>make
(Cached make -did not change the compiler or the files to be built)
The CMakeLists.txt:
set(TARGET_GROUP test CACHE STRING "Group to build")
if(TARGET_GROUP STREQUAL production)
# ARM Lib
include("arm-gnu.cmake")
else()
include("win-gcc-for-testing.cmake")
endif()
# include the files based on the TARGET_GROUP value
# ...
Current Solution
Currently, I have a temporary solution by making a separate folder for each building type and they work perfectly.
The question
Is the current solution (making two build directories each is for a different environment) right in terms of best practices? If not, what could be a better one?
As #Tsyvarev says, you have to use different directories if you want different builds. Here you are trying to build both in the same build directory. Instead, create a subdirectory test to build the -DTARGET_GROUP=test, and a different subdirectory prod to build the -DTARGET_GROUP=production:
Project> mkdir test
Project> cd test
Project\test> cmake -G"MinGW Makefiles" -DTARGET_GROUP=test ..
Project\test> cd ..
Project> mkdir prod
Project> cd prod
Project\prod> cmake -G"MinGW Makefiles" -DTARGET_GROUP=production ..
Of course you can call the directories whatever you like.
Since you'd like this to integrate into VSCode, do the configuration change with the CMake build kits, which is what sets the compiler prior to calling CMake. You can specify additional user kit definitions, and in the VSCode interface choose between compiler kits.
Rewrite the CMake files just enough to condition everything else on the selection of compiler.
THEN, the VSCode cmake-tools extension supports variable expansion for the name of the build directory. Among the options are ${buildKit} and ${buildKitTargetArch}. Make this suffix part of the Build Directory setting (your choice of whether to set this only in your workspace, or more globally on your system).
Now, when you switch kits, CMake will pick up the directory change and happily exist with two different build directories.
Alternatively, cmake-tools now provides variants, which could be used to add additional Production and Test to the normal Release, Debug, RelWithDebInfo, etc. There are additional build directory expansion variables for information from the currently selected variant.
I'm trying to add a target to generate API doc with Doxygen to my CMake project by find_package(Doxygen ...) and doxygen_add_docs(). I'm in a MSYS2 environment on Windows 10. For some reason CMake and Doxygen seem to not handle paths in the expected way (see the example).
At first, Doxygen complains that it cannot create the output directory. The DOXYGEN_OUTPUT_DIRECTORY prepared by CMake is a Windows path with regular forward slashes. Doxygen seems to not recognize this as an absolute path and prepends it with its working directory in the Unix format (/c/Users/...). I tried this by executing the generated target as well as calling Doxygen manually with the generated Doxyfile.doc. It works if I convert the path to a Unix path with cygpath.
The second problem is about finding dot. I have GraphViz installed as a native Windows package and generally the MSYS2 CMake finds this. Then, in the FindDoxygen.cmake DOXYGEN_DOT_PATH is set as the path portion of the dot executable and is modified by file(TO_NATIVE_PATH ...) because I'm on Windows. Trying this manually I could see that it sets that path to "C:/Program Files (x86)/Graphviz/bin" and converts it to "C:/Program\ Files\ (x86)/Graphviz/bin". The latter ends up in Doxyfile.doc. If I remove the backslashes there, it works. I suppose Doxygen considers these backslashes which are meant to escape the spaces as path separators.
For the first problem I have a (hopefully) portable workaround, but the second I can only fix if I manually repeat the retrieval of DOXYGEN_DOT_PATH from the Find module without the conversion step. This doesn't feel like a good solution.
Do I miss something here about path handling in CMake, e.g. some documentation or setting/policy?
Is this anyways the expected behavior, esp. for file(TO_NATIVE_PATH ...), in MSYS2?
Example
Very basic example: Just a CMakeLists.txt to generate Makefiles and invoke Doxygen. The output of make doc shows the 2 problems described above - the error is for #1, the warning for #2.
CMakeLists.txt
cmake_minimum_required(VERSION 3.19)
project(DoxyTest VERSION 0.1)
find_package(Doxygen OPTIONAL_COMPONENTS dot)
doxygen_add_docs(doc)
Trying to build the doc target
$ cmake -G"MSYS Makefiles" ..
-- The C compiler identification is GNU 10.2.0
-- The CXX compiler identification is GNU 10.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/msys64/mingw64/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/msys64/mingw64/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Doxygen: C:/msys64/usr/bin/doxygen.exe (found version "1.9.1 (ec8203f43232e7e7b16b1c85351c7c48d128f924)") found components: doxygen dot
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/myUser/tmp/foo/build
$ make doc
Scanning dependencies of target doc
[100%] Generate API documentation for doc
warning: the dot tool could not be found at C:/Program\ Files\ (x86)/Graphviz/bin
Doxygen version used: 1.9.1 (ec8203f43232e7e7b16b1c85351c7c48d128f924)
error: Could not create output directory /C/Users/myUser/tmp/foo/C:/Users/myUser/tmp/foo/build/html
Exiting...
make[3]: *** [CMakeFiles/doc.dir/build.make:78: CMakeFiles/doc] Error 1
make[2]: *** [CMakeFiles/Makefile2:95: CMakeFiles/doc.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:102: CMakeFiles/doc.dir/rule] Error 2
make: *** [Makefile:137: doc] Error 2
It turned out that the proper Doxygen package was not installed in the MSYS2 environment.
I use the MinGW64 shell, which uses the binaries from the mingw-w64-x86_64-* packages. The CMake output from the question shows that the binaries for the C and CXX compilers are under C:/msys64/mingw64/ (as well as the CMake binary) while Doxygen is in C:/msys64/usr/bin/.
Installing mingw-w64-x86_64-doxygen solved the issue. Now, the CMake output shows the mingw64 path also for Doxygen in the MSYS2 MinGW64-bit shell and API doc generation works flawlessly. Trying the MSYS2 MSYS shell also works fine with CMake using binaries from C:/msys64/usr/bin/.
I have a C++ project where I do not want to specify a "default" compiler, since it needs to be compiled with many different compilers in different contexts. (In unit testing and end-to-end testing, I do test it with a few different compilers.)
I tried to implement this in CMake by requiring that the user set the environment variable CXX before the initial CMake configuration (executing cmake). (I also have it drop a file to store the value to ensure that any subsequent invocation of make has the same value of CXX set, but that's irrelevant to the rest of the question.)
However, this doesn't actually work. Here is a minimal example and the execution output.
CMake configuration file:
project(test)
if(DEFINED ENV{CXX})
message("\$CXX = ${CXX}")
else()
message(SEND_ERROR "\$CXX must be defined by the user to compile this project.")
endif()
add_executable(test)
First execution of cmake:
-- The C compiler identification is GNU 4.3.4
-- The CXX compiler identification is GNU 4.3.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- 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: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
$CXX =
-- Configuring done
CMake Error at CMakeLists.txt:9 (add_executable):
No SOURCES given to target: test
-- Build files have been written to: /hnfs/torcfs03n06a/vol/ret_users_sasquire/inactive/bugs/cmake
Second invocation of cmake in the same directory (with no cleanup):
CMake Error at CMakeLists.txt:6 (message):
$CXX must be defined to compile this project.
-- Configuring incomplete, errors occurred!
So the test whether CXX is defined is clearly working the second time, but not the first time.
Two questions:
How should I be implementing this?
I think that it is a somewhat reasonable behavior for cmake to set CXX internally if it wasn't set by the user, and I suspect that's what's happening in the first case. But why are the first and second runs different?
Some comments on item 1:
There are some obvious things, like introducing my own environment variable that is used to determine the compiler that cmake won't set on its own. But ideally I would just be able to get CMake to forego defining CXX, for example. Or perhaps there is functionality along the lines of GNU make's origin function, which can distinguish between variables set in the environment and variables set by default or in the makefile.
If the answer is basically "don't do that" (i.e. don't make the user define the compiler), then I am not going to consider it a constructive answer.
Comments on item 2:
To me, this looks like a bug in CMake, where it sets CXX while detecting the C++ compiler, and then it does not unset that variable afterwards. But is there a different way to look at this? Or is there documentation regarding this?
Just check CXX environment variable before project() call:
if(DEFINED ENV{CXX})
message("\$CXX = ${CXX}")
else()
message(SEND_ERROR "\$CXX must be defined by the user to compile this project.")
endif()
project(test)
CXX variable is used by CMake when detecting C++ compiler, and exactly project() call triggers that detection. So, why do you check the variable after the project() call if bad things have already happened?
As for setting the CXX environment variable internally by CMake, I would suggest to not care about that.
Anywhere, setting this variable for other purposes (not for compiler detection) would contradict with CMake usage of that variable.
For finding out which C++ compiler is used after the project() call, it is simpler to read CMAKE_CXX_COMPILER CMake variable.