Cmake Test for Processor Feature

CMake test for processor feature

execute_process(COMMAND cat /proc/cpuinfo
COMMAND head -n 19
COMMAND tail -1
COMMAND grep -c rdtscp
OUTPUT_VARIABLE OUT)

How to detect target architecture using CMake?

So I devised a rather creative solution to my problem... it appears that CMake has no functionality to detect the target architecture whatsoever.

Now, we know we can easily do this in C because symbols like __i386__, __x86_64__, etc., will be defined depending on your environment. Fortunately CMake has a try_run function which will compile and run an arbitrary C source code file during the configure stage.

We could then write a small program which uses a bunch of ifdefs and writes the architecture name to the console as a string. The only problem is that this only works if the host and target system are the same... it can't work during cross compilation because while you can compile the binary, you can't run it to see its output.

Here's where things get interesting. We can exploit the C preprocessor to get the necessary information by deliberately writing a broken C program... we use the original concept of writing the architecture name to the console based on ifdefs but instead of doing that, we'll simply place an #error preprocessor directive in place of a printf call.

When CMake's try_run function compiles the C file, compilation will always fail, but whatever message we placed in the #error directive will show up in the compiler's error output, which try_run returns to us.

Therefore, all we have to do is parse the architecture name from the compiler's error output using some CMake string commands, and we can retrieve the target architecture... even when cross compiling.

The OS X specific part of the code mostly uses CMAKE_OSX_ARCHITECTURES to determine the target architecture, but in the case it's unspecified it will use the same code as other systems and correctly return x86_64 (for modern systems on which that is the compiler's default) or i386 (for older OS X systems such as Leopard).

I've tested and verified this works on Windows, OS X and Linux using Visual Studio 9 and 10 generators (x86, x86_64, ia64), Xcode, NMake, MSYS Makefiles and Unix Makefiles. The correct result is returned every time.

Notice: This solution can fail if you deliberately do things like pass -m32 or -m64 to your compiler, or other flags that may affect the target architecture (is there a way to pass all environment settings through to try_run?); this is not something I've tested. As long as you're using the default settings for your generator and all targets are being compiled for the same architecture you should be OK.

The full source code for my solution can be found at GitHub: https://github.com/petroules/solar-cmake/blob/master/TargetArch.cmake

From CMake setup 'make' to use '-j' option by default

Via setting the CMAKE_MAKE_PROGRAM variable you want to affect the build process. But:

  1. This variable affects only the build via cmake --build, not on native tool (make) call:

    The CMAKE_MAKE_PROGRAM variable is set for use by project code. The value is also used by the cmake(1) --build and ctest(1) --build-and-test tools to launch the native build process.

  2. This variable should be a CACHEd one. It is used in such way by make-like generators:

    These generators store CMAKE_MAKE_PROGRAM in the CMake cache so that it may be edited by the user.

    That is, you need to set this variable with

    set(CMAKE_MAKE_PROGRAM <program> CACHE PATH "Path to build tool" FORCE)
  3. This variable should refer to the executable itself, not to a program with arguments:

    The value may be the full path to an executable or just the tool name if it is expected to be in the PATH.

    That is, value "make -j 2" cannot be used for that variable (splitting arguments as list

    set(CMAKE_MAKE_PROGRAM make -j 2 CACHE PATH "Path to build tool" FORCE)

    wouldn't help either).

In summary, you may redefine the behavior of cmake --build calls with setting the CMAKE_MAKE_PROGRAM variable to the script, which calls make with parallel options. But you may not affect the behavior of direct make calls.

How to detect if 64 bit MSVC with cmake?

There are several ways - also used by CMake itself - that will check for "not 64Bit":

if(NOT "${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
...
endif()

if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
...
endif()

if(NOT CMAKE_CL_64)
...
endif()

References

  • CMAKE_GENERATOR
  • CMAKE_SIZEOF_VOID_P
  • CMAKE_CL_64

CMake conditional preprocessor define on code

You can simplify things by avoiding creating the dummy targets and removing the config file. Instead, if you pass the requirements via the command line when you invoke CMake (or via the CMake GUI), you can run make only once.

For example, you could add the following to your CMakeLists.txt:

option(WITH_FEATURE_A "Option description" ON)
option(WITH_FEATURE_B "Option description" OFF)

if(WITH_FEATURE_A)
add_definitions(-DUSE_FEATURE_A)
endif()
if(WITH_FEATURE_B)
add_definitions(-DUSE_FEATURE_B)
endif()

By default, if you just run CMake, it will set the CMake variable WITH_FEATURE_A to ON which consequently adds USE_FEATURE_A as a preprocessor definition to the build. USE_FEATURE_B is undefined in the code.

This would be equivalent to doing #define USE_FEATURE_A in your code.


If you really need the equivalent of

#define USE_FEATURE_A 1
#define USE_FEATURE_B 0

then in your CMakeLists.txt you can do:

option(WITH_FEATURE_A "Option description" ON)
option(WITH_FEATURE_B "Option description" OFF)

if(WITH_FEATURE_A)
add_definitions(-DUSE_FEATURE_A=1)
else()
add_definitions(-DUSE_FEATURE_A=0)
endif()
if(WITH_FEATURE_B)
add_definitions(-DUSE_FEATURE_B=1)
else()
add_definitions(-DUSE_FEATURE_B=0)
endif()

To change these defaults from the command line, simply do (e.g.):

cmake . -DWITH_FEATURE_A=OFF -DWITH_FEATURE_B=ON
make

Once a variable has been set via the command line this way, it is cached and will remain unchanged until either it is overwritten with a different value on the command line, or you delete the CMakeCache.txt file in your build root.



Response to update:

As @Peter noted, you appear to be mixing up CMake variables (the WITH_FEATURE... ones) and the preprocessor definitions (the USE_FEATURE... ones). You can as suggested resolve all the dependencies between options first, then set the resulting preprocessor definitions, or in this case where the flow is quite straightforward, just do it all in one go:

if(WITH_FEATURE_A)
message(STATUS "WITH_FEATURE_A")
add_definitions(-DUSE_FEATURE_A=1)
set(WITH_FEATURE_B ON)
endif()

if(WITH_FEATURE_B)
message(STATUS "WITH_FEATURE_B")
add_definitions(-DUSE_FEATURE_B=1)
set(WITH_FEATURE_D ON)
endif()

if(WITH_FEATURE_C)
message(STATUS "WITH_FEATURE_C")
add_definitions(-DUSE_FEATURE_C=1)
set(WITH_FEATURE_D ON)
endif()

if(WITH_FEATURE_D)
message(STATUS "WITH_FEATURE_D")
add_definitions(-DUSE_FEATURE_D=1)
endif()


Define preprocessor macro through CMake?

For a long time, CMake had the add_definitions command for this purpose. However, recently the command has been superseded by a more fine grained approach (separate commands for compile definitions, include directories, and compiler options).

An example using the new add_compile_definitions:

add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION})
add_compile_definitions(WITH_OPENCV2)

Or:

add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION} WITH_OPENCV2)

The good part about this is that it circumvents the shabby trickery CMake has in place for add_definitions. CMake is such a shabby system, but they are finally finding some sanity.

Find more explanation on which commands to use for compiler flags here: https://cmake.org/cmake/help/latest/command/add_definitions.html

Likewise, you can do this per-target as explained in Jim Hunziker's answer.

cmake loads cpu without any effect

You can try adding the --trace option to the cmake call. The problem will still exist, but at least you should see then what is taking so long and can then further investigate. The --debug-output option might also help.

/usr/bin/cmake -DCMAKE_BUILD_TYPE=Debug --trace --debug-output /home/sergey/projects/project-test/


Related Topics



Leave a reply



Submit