Specify CMake generator unless explicitly passed as command argument by user - cmake

In all of the following, I'm using Windows, so WIN32 is always defined in CMake.
I have a CMakeLists.txt file which does its job fine, and I'm using a Preload.CMake file to specify a bunch of stuff, including a certain generator depending on circumstances:
if( WIN32 )
message( "Current generator: ${CMAKE_GENERATOR}" ) # For debugging purposes
if( NOT COMMAND cl OR NOT COMMAND nmake )
set( CMAKE_CXX_COMPILER "g++" )
set( CMAKE_GENERATOR "MinGW Makefiles" CACHE STRING "" FORCE )
set( CMAKE_MAKE_PROGRAM "make" )
message( "MSVC compiler could not be found, attempting with g++ and MinGW makefiles." )
endif( )
endif( )
This allows a Windows user with no Visual Studio to run cmake .. instead of a whole cmake .. -G "MinGW Makefiles".
It works pretty well, here is the output when cmake .. is run from an empty directory (no cache, no nothing):
Current generator:
MSVC compiler could not be found, attempting with g++ and MinGW makefiles.
Windows detected, forcing static libs.
-- The CXX compiler identification is GNU 8.2.0
-- Check for working CXX compiler: C:/MinGW/bin/g++.exe
-- Check for working CXX compiler: C:/MinGW/bin/g++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/SAYENS/Desktop/picross/build
The problem with this is when I want to specify a generator through the command line. Here is what happens when I run cmake .. -G "MSYS Makefiles" from a MSYS terminal (empty directory, no cache):
Current generator:
MSVC compiler could not be found, attempting with g++ and MinGW makefiles.
CMake Error: Error: generator : MSYS Makefiles
Does not match the generator used previously: MinGW Makefiles
Either remove the CMakeCache.txt file and CMakeFiles directory or choose a different binary directory.
(There is no such file as CMakeCache.txt or a CMakeFiles directory, but explicitly specifying a generator in the command line, that is different from the one specified in Preload.CMake, seems to be enough of a source of confusion to print out this message.)
I thought I'd be able to work around the issue by "catching" the value of the -G argument with CMAKE_GENERATOR, but it turns out I can't, as per the first output line Current generator:.
How can I work this out? I tried looking for a way to parse command line arguments, but found none that doesn't involve using a wrapper script, which I'd like to avoid resorting to.

Set the generator name in the environment variable CMAKE_GENERATOR. The documentation says:
Specifies the CMake default generator to use when no generator is
supplied with -G. If the provided value doesn’t name a generator known
by CMake, the internal default is used. Either way the resulting
generator selection is stored in the CMAKE_GENERATOR variable.
Some generators may be additionally configured using the environment
variables:
CMAKE_GENERATOR_PLATFORM
CMAKE_GENERATOR_TOOLSET
CMAKE_GENERATOR_INSTANCE

Related

cmake move build files in a subdirectory after configuring and building [duplicate]

I'm using cmake to compile a C++ project, and I want cmake to generate all the output files(metafiles like Makefile used to create binaries) in the build folder. I've checked all the answers in How do I make cmake output into a 'bin' dir?, none of them worked for me(suprisingly!). Files are generated in the root folder instead of in the build folder, what's wrong here? I guess I must have missed something.
Code Structure
➜ cmake-test tree .
.
├── CMakeLists.txt
└── hello.cpp
0 directories, 2 files
CMakeLists.txt
# Specify the minimum version for CMake
cmake_minimum_required(VERSION 3.11)
# Project's name
project(hello)
# Set the output folder where your program will be created
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# The following folder will be included
include_directories("${PROJECT_SOURCE_DIR}")
add_executable(hello ${PROJECT_SOURCE_DIR}/hello.cpp)
Build Commands and Outputs
➜ cmake-test cmake .
-- The C compiler identification is GNU 8.2.0
-- The CXX compiler identification is GNU 8.2.0
-- 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
-- Configuring done
-- Generating done
-- Build files have been written to: /home/searene/CLionProjects/cmake-test
➜ cmake-test ls
bin CMakeCache.txt CMakeFiles cmake_install.cmake CMakeLists.txt hello.cpp Makefile
cmake version
➜ cmake-test cmake --version
cmake version 3.11.4
CMake suite maintained and supported by Kitware (kitware.com/cmake).
OS
Linux
The usual way to do this, rather than changing variables to set the path, is simply to create the output directory, change to it, and run cmake from there. So instead of cmake . you usually have cmake .. or similar.
I understand the initial impulse to say "But I expect my build system to write output somewhere else." But CMake is not usually used in the way you were initially expecting, and other people who run your CMake build won't expect what you were expecting, so it's probably best to just use the built-in, default behavior, which is to put the output wherever cmake was run.
Put another way: You are fighting against the tool. Don't do that.
Disclaimer: I recommend going with #john-zwinck's answer.
By default, cmake uses the current working directory as build directory and whatever path you provide as source directory. So the normal way of achieving your goal is
create the build directory (mkdir build)
go there (cd build)
call cmake with the source dir as argument (cmake path/to/source)
BUT there is another way, as far as I know not documented in the cmake docs and only kept for compatibility reasons or internal usage, that some people are using. The -B and -H flags
cmake -Hpath/to/source -Bpath/to/build
or even from the source dir
cmake . -Bbuild
Important: no space after -B.
CMake 3.19.1 (not sure how about older ones) has following option (from docs):
cmake [<options>] -S <path-to-source> -B <path-to-build>
Uses as the build tree and as the
source tree. The specified paths may be absolute or relative to the
current working directory. The source tree must contain a
CMakeLists.txt file. The build tree will be created automatically if
it does not already exist. For example:
cmake -S src -B build

Create Portable CMake/MingGW(G++) [duplicate]

I have a problem with this CMakeLists.txt file:
cmake_minimum_required(VERSION 2.6)
SET(CMAKE_C_COMPILER C:/MinGW/bin/gcc)
SET(CMAKE_CXX_COMPILER C:/MinGW/bin/g++)
project(cmake_test)
add_executable(a.exe test.cpp)
Calling cmake with: cmake -G "MinGW Makefiles" , it fails with the following output:
c:\Users\pietro.mele\projects\tests\buildSystem_test\cmake_test>cmake -G "MinGW Makefiles" .
-- The C compiler identification is GNU 4.6.1
-- The CXX compiler identification is GNU 4.6.1
-- Check for working C compiler: C:/MinGW/bin/gcc
CMake Error: your C compiler: "C:/MinGW/bin/gcc" was not found. Please set CMAKE_C_COMPILER to a valid compiler path or name.
CMake Error: Internal CMake error, TryCompile configure of cmake failed
-- Check for working C compiler: C:/MinGW/bin/gcc -- broken
CMake Error at C:/Program Files (x86)/CMake 2.8/share/cmake-2.8/Modules/CMakeTestCCompiler.cmake:52 (MESSAGE):
The C compiler "C:/MinGW/bin/gcc" is not able to compile a simple test
program.
CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
CMakeLists.txt:10 (project)
CMake Error: your C compiler: "C:/MinGW/bin/gcc" was not found. Please set CMAKE_C_COMPILER to a valid compiler path or name.
CMake Error: your CXX compiler: "C:/MinGW/bin/g++" was not found. Please set CMAKE_CXX_COMPILER to a valid compiler path or name.
-- Configuring incomplete, errors occurred!
However the gcc compiler is in C:/MinGW/bin/ and it works.
Any idea?
Platform:
Windows 7
MinGW/GCC 4.6
Never try to set the compiler in the CMakeLists.txt file.
See the CMake FAQ about how to use a different compiler:
https://gitlab.kitware.com/cmake/community/wikis/FAQ#how-do-i-use-a-different-compiler
(Note that you are attempting method #3 and the FAQ says "(avoid)"...)
We recommend avoiding the "in the CMakeLists" technique because there are problems with it when a different compiler was used for a first configure, and then the CMakeLists file changes to try setting a different compiler... And because the intent of a CMakeLists file should be to work with multiple compilers, according to the preference of the developer running CMake.
The best method is to set the environment variables CC and CXX before calling CMake for the very first time in a build tree.
After CMake detects what compilers to use, it saves them in the CMakeCache.txt file so that it can still generate proper build systems even if those variables disappear from the environment...
If you ever need to change compilers, you need to start with a fresh build tree.
I had similar problem as Pietro,
I am on Window 10 and using "Git Bash".
I tried to execute >>cmake -G "MinGW Makefiles", but I got the same error as Pietro.
Then, I tried >>cmake -G "MSYS Makefiles", but realized that I need to set my environment correctly.
Make sure set a path to C:\MinGW\msys\1.0\bin and check if you have gcc.exe there. If gcc.exe is not there then you have to run C:/MinGW/bin/mingw-get.exe and install gcc from MSYS.
After that it works fine for me
Using with FILEPATH option might work:
set(CMAKE_CXX_COMPILER:FILEPATH C:/MinGW/bin/gcc.exe)
I had the same issue. And in my case the fix was pretty simple. The trick is to simply add the ".exe" to your compilers path. So, instead of :
SET(CMAKE_C_COMPILER C:/MinGW/bin/gcc)
It should be
SET(CMAKE_C_COMPILER C:/MinGW/bin/gcc.exe)
The same applies for g++.

CMake for non-C project on host without a C compiler

I'd like to use CMake to generate makefiles for non C project. I don't need a C compiler to build my project. As a matter of fact, I don't have a C compiler installed on the host machine.
My CMakeLists.txt looks like:
cmake_minimum_required (VERSION 2.6)
project (the_thing.html)
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules/cmake-pandocology")
INCLUDE(pandocology)
add_document(
TARGET the_thing
OUTPUT_FILE the_thing.html
SOURCES the_thing.md
)
When I run cmake on my windows machine:
$ mkdir dict && cd dist
$ cmake .. -G"Unix Makefiles"
-- The C compiler identification is unknown
-- The CXX compiler identification is unknown
CMake Error at CMakeLists.txt:2 (project):
No CMAKE_C_COMPILER could be found.
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.
CMake Error at CMakeLists.txt:2 (project):
No CMAKE_CXX_COMPILER could be found.
Tell CMake where to find the compiler by setting either the environment
variable "CXX" or the CMake cache entry CMAKE_CXX_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 ".../dist/CMakeFiles/CMakeOutput.log".
See also ".../dist/CMakeFiles/CMakeError.log".
Those two logfiles give no additional clue. How do I fix that project for it to ignore the absence of a C (and C++) compiler?
You need to explicitly say there are no languages.
project("the_thing.html"
LANGUAGES
NONE
)
That's from one of my projects, but it uses modern CMake (your minimum version is 2.6). The above may work for you, but if not this should do it:
project("the_thing.html" NONE)

How to pass a compile flag to cmake initial compiler test?

I'm trying to use CMake for building a project which uses the MSPGCC cross-compiler for a MSP430 microcontroller. To successfully compile any simple program with it, we need to pass a compile flag indicating the target processor, or else it fails like this:
$ msp430-gcc -o test test.c
In file included from test.c:1:0:
/usr/local/lib/gcc/msp430/4.6.3/../../../../msp430/include/msp430.h:813:2: warning: #warning Unable to identify and include MCU header, use -mmcu=MCU [-Wcpp]
/usr/local/lib/gcc/msp430/4.6.3/../../../../msp430/bin/ld: cannot open linker script file memory.x: No such file or directory
collect2: ld returned 1 exit status
Hence, if I indicate the processor using the -mmcu switch it works fine. The problem is, although I'm already specifying this in my CMakeLists.txt file:
cmake_minimum_required (VERSION 2.6)
project (test-project C)
set (SOURCES
test.c
)
add_executable (test-project ${SOURCES})
set (CPU_FLAG "-mmcu=msp430f148")
set (CMAKE_C_FLAGS ${CPU_FLAG})
set (CMAKE_EXE_LINKER_FLAGS ${CPU_FLAG})
CMake complains the compiler failed the test to compile a simple program, which I bet is happening because it is probably not using the -mmcu switch (note the message about not being able to open linker script file memory.x):
$ cd ~/git/test-project
$ mkdir build
$ cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=../msp430.cmake ..
-- The C compiler identification is GNU 4.6.3
-- Check for working C compiler: /usr/local/bin/msp430-gcc
-- Check for working C compiler: /usr/local/bin/msp430-gcc -- broken
CMake Error at /usr/share/cmake-2.8/Modules/CMakeTestCCompiler.cmake:52 (MESSAGE):
The C compiler "/usr/local/bin/msp430-gcc" is not able to compile a simple
test program.
It fails with the following output:
Change Dir: /home/claudio/git/test-project/build/CMakeFiles/CMakeTmp
Run Build Command:/usr/bin/gmake "cmTryCompileExec2889462763/fast"
/usr/bin/gmake -f CMakeFiles/cmTryCompileExec2889462763.dir/build.make
CMakeFiles/cmTryCompileExec2889462763.dir/build
gmake[1]: Entering directory
`/home/claudio/git/test-project/build/CMakeFiles/CMakeTmp'
/usr/bin/cmake -E cmake_progress_report
/home/claudio/git/test-project/build/CMakeFiles/CMakeTmp/CMakeFiles 1
Building C object
CMakeFiles/cmTryCompileExec2889462763.dir/testCCompiler.c.o
/usr/local/bin/msp430-gcc -o
CMakeFiles/cmTryCompileExec2889462763.dir/testCCompiler.c.o -c
/home/claudio/git/test-project/build/CMakeFiles/CMakeTmp/testCCompiler.c
Linking C executable cmTryCompileExec2889462763
/usr/bin/cmake -E cmake_link_script
CMakeFiles/cmTryCompileExec2889462763.dir/link.txt --verbose=1
/usr/local/bin/msp430-gcc
CMakeFiles/cmTryCompileExec2889462763.dir/testCCompiler.c.o -o
cmTryCompileExec2889462763 -rdynamic
/usr/local/lib/gcc/msp430/4.6.3/../../../../msp430/bin/ld: cannot open
linker script file memory.x: No such file or directory
collect2: ld returned 1 exit status
gmake[1]: Leaving directory
`/home/claudio/git/test-project/build/CMakeFiles/CMakeTmp'
gmake[1]: *** [cmTryCompileExec2889462763] Error 1
gmake: *** [cmTryCompileExec2889462763/fast] Error 2
CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
CMakeLists.txt:3 (project)
-- Configuring incomplete, errors occurred!
Just for the record, my toolchain file is as follows, and my PATH variable allows it to find the compiler binaries at /usr/local/bin:
# the name of the target operating system
#SET(CMAKE_SYSTEM_NAME Linux)
# which C and C++ compiler to use
SET(CMAKE_C_COMPILER msp430-gcc)
SET(CMAKE_CXX_COMPILER msp430-g++)
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/local/msp430)
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
All that said, can anyone tell me how to check which compile flags CMake is using to carry the compiler test, and how can we pass custom flags (like -mmcu, for instance) so it doesn't fail it?
According to the Docs:
http://www.cmake.org/Wiki/CMake_Cross_Compiling#The_toolchain_file
you should use the CMakeForceCompiler thing
INCLUDE(CMakeForceCompiler)
# this one is important
SET(CMAKE_SYSTEM_NAME eCos)
# specify the cross compiler
CMAKE_FORCE_C_COMPILER(arm-elf-gcc GNU)
CMAKE_FORCE_CXX_COMPILER(arm-elf-g++ GNU)
# where is the target environment
SET(CMAKE_FIND_ROOT_PATH /home/alex/src/ecos/install )
# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
(copy&paste from the docs)
Using it fine here for my MSP430 too
The other answer here is outdated.
The toolchain file should include the required flags in the appropriate CMAKE_<KIND>_FLAGS(_<CONFIG>)_INIT variables, like so:
set(CMAKE_C_FLAGS_INIT "-mmcu=msp430f148")
set(CMAKE_CXX_FLAGS_INIT "-mmcu=msp430f148")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-mmcu=msp430f148")
CMake's compiler detection routines will use these flags when compiling a test executable. The full list is available in the CMake variables documentation, but the full list (at time of writing) is:
CMAKE_<LANG>_FLAGS_<CONFIG>_INIT
CMAKE_<LANG>_FLAGS_INIT
CMAKE_EXE_LINKER_FLAGS_<CONFIG>_INIT
CMAKE_EXE_LINKER_FLAGS_INIT
CMAKE_MODULE_LINKER_FLAGS_<CONFIG>_INIT
CMAKE_MODULE_LINKER_FLAGS_INIT
CMAKE_SHARED_LINKER_FLAGS_<CONFIG>_INIT
CMAKE_SHARED_LINKER_FLAGS_INIT
CMAKE_STATIC_LINKER_FLAGS_<CONFIG>_INIT
CMAKE_STATIC_LINKER_FLAGS_INIT
Where <CONFIG> is any ALL CAPS config name including, but not limited to, DEBUG, RELWITHDEBINFO, MINSIZEREL, and RELEASE. The non-<CONFIG> variants apply to all configurations and are augmented by the <CONFIG> variants.
And, where <LANG> is any of the languages known to enable_language(), currently including CXX, C, CUDA, OBJC, OBJCXX, Fortran, HIP, ISPC, and ASM. The current list may be found in the enable_language documentation.

cmake: Selecting a generator within CMakeLists.txt

I would like to force CMake to use the "Unix Makefiles" generator from within CMakeLists.txt.
This is the command I use now.
cmake -G "Unix Makefiles" .
I would like it to be this.
cmake .
When running on windows with VC installed and a custom tool-chain.
I would expect to be-able to set the generator in the CMakeLists.txt file.
Maybe something like this.
set(CMAKE_GENERATOR "Unix Makefiles")
Here is what worked for me - create a file called PreLoad.cmake in your project dir containing this:
set (CMAKE_GENERATOR "Unix Makefiles" CACHE INTERNAL "" FORCE)
It seems to me that the variable CMAKE_GENERATOR is set too late if set in the CMakeLists.txt. If you use (even at the beginning of CMakeLists.txt)
set(CMAKE_GENERATOR "Ninja")
message("generator is set to ${CMAKE_GENERATOR}")
you can see in the output something like
% cmake ../source
-- The C compiler identification is GNU 4.9.2
...
-- Detecting CXX compile features - done
generator is set to Ninja
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/build
So the variable is only set at the very end of the generation procedure. If you use something like
set(CMAKE_GENERATOR "Ninja" CACHE INTERNAL "" FORCE)
in CMakeLists.txt, then in the very first run of cmake ../source (without -G) the default generator is used. The variable CMAKE_GENERATOR is stored in the cache, though. So if you rerun cmake ../source afterwards, it will use the generator as specified in the CMAKE_GENERATOR variable in the cache.
This is surely not the most elegant solution, though ;-) Maybe use a batch file that will actually execute the cmake -G generator for the user...
This is not what I get, when I run the same command, cmake will look for a gcc compiler / make utility. If the PATH is not set up correctly it will fail with something like:
D:\Development\build>cmake -G "Unix Makefiles" ..\source
CMake Error: CMake was unable to find a build program corresponding to "Unix Makefiles". CMAKE_MAKE_PROGRAM is not set.
You probably need to select a different build tool.
CMake Error: Error required internal CMake variable not set, cmake may be not be built correctly.
Missing variable is:
CMAKE_C_COMPILER_ENV_VAR
CMake Error: Error required internal CMake variable not set, cmake may be not be built correctly.
Missing variable is:
CMAKE_C_COMPILER
CMake Error: Could not find cmake module file:D:/Development/build/CMakeFiles/CMakeCCompiler.cmake
CMake Error: Error required internal CMake variable not set, cmake may be not be built correctly.
Missing variable is:
CMAKE_CXX_COMPILER_ENV_VAR
CMake Error: Error required internal CMake variable not set, cmake may be not be built correctly.
Missing variable is:
CMAKE_CXX_COMPILER
CMake Error: Could not find cmake module file:D:/Development/build/CMakeFiles/CMakeCXXCompiler.cmake
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage
-- Configuring incomplete, errors occurred!
when gcc / mingw is in the path then everything works fine. So could you provide more information as to your PATH variable or CMAKE version?
You need to set the generator at the Generate stage so it is written into the cache.
You only need to run this command once for the first configuration
cmake .. -DCMAKE_GENERATOR:INTERNAL=Ninja
This will configure Ninja as the default generator.
Later you can simply run
cmake ..
And it would use the Ninja generator as default
You can read more about it under Running CMake from the command line
When running cmake from the command line, it is possible to specify command line options to cmake that will set values in the cache. This is done with a -DVARIABLE:TYPE=VALUE syntax on the command line. This is useful for non-interactive nightly test builds.
CMake 3.19 introduces a new feature - presets. So, to select proper generator automatically, you can specify it name in CMakePresets.json.
Full description for these files available here: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html