What is AC_COMPUTE_INT for CMake? - cmake

For autotools there is a Macro called AC_COMPUTE_INT. It can be used to compute (detect) an integral compile time expression. How to do that in CMake?
A naive approach could be using try_run to output the number. However that breaks cross compilation and AC_COMPUTE_INT works with cross compilation by bisecting the number with compilation steps.
Edit:
The autotools AC_COMPUTE_INT works as follows:
It has a short-cut when not cross compiling and just runs a program to make things faster.
It repeatedly compiles a program containing (something similar to) char somearray[boolean_compile_time_expression ? 1 : -1]; to learn the value of boolean_compile_time_expression.
It first uses such an expression to check the sign of the integer expression being asked.
Then it looks for a bound of the integer expression by repeatedly checking whether it is smaller than 2 * lastbound + 1 (positive case).
Once it found an upper and lower bound, it does a binary search inside to get the actual value.
It usually takes less than 50 compile tests. (It's a bit worse than testing for each bit individually in the worst case.) For many (in particular small) values, it takes much less tests.
Since it doesn't use anything but the equivalent of try_compile (in the cross case), it is as portable as try_compile.
AC_CHECK_SIZEOF uses AC_COMPUTE_INT and thus inherits its portability properties.

After a few dumps of gcc intermediate compilation steps I've ended up with -fdump-tree-original. Which seems quite easy to parse and contains values of already evaluated expressions and sizeof.
Example C source:
#define FANCY_VALUE sizeof(int) * 10
int main(int argc, char **argv)
{
return FANCY_VALUE;
}
Result of gcc -fdump-tree-original example.c:
;; Function main (null)
;; enabled by -tree-original
{
return 40;
}
return 0;
Sooo... One of probably non-portable and gcc specific ways might look like this:
cmake_minimum_required(VERSION 3.5)
# AC_COMPUTE_INT function doing all the lifting
function(AC_COMPUTE_INT OUTPUT_VAR INPUT_EXP)
set(C_FILE ${CMAKE_BINARY_DIR}/ac_computer.c)
set(DUMP_FILE ${CMAKE_BINARY_DIR}/ac_computer.dump)
file(WRITE ${C_FILE}
"int main(int argc, char **argv) { return ${INPUT_EXP};}"
)
execute_process(
COMMAND ${CMAKE_C_COMPILER} -c -fdump-tree-original=${DUMP_FILE} ${C_FILE}
)
file(READ ${DUMP_FILE} AC_COMPUTER_DUMP)
string(REGEX MATCH "return [0-9]+" DUMP_MATCH ${AC_COMPUTER_DUMP})
string(REGEX REPLACE "return " "" DUMP_MATCH ${DUMP_MATCH})
set(${OUTPUT_VAR} "${DUMP_MATCH}" PARENT_SCOPE)
endfunction()
set(MY_FANCY_INPUT "sizeof(int) * 8 + 1")
AC_COMPUTE_INT(MY_FANCY_OUTPUT ${MY_FANCY_INPUT})
message(STATUS "Expression: ${MY_FANCY_INPUT}")
message(STATUS "Evaluates to: ${MY_FANCY_OUTPUT}"
Which brings us the following:
$ cmake ../
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.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
-- Expression: sizeof(int) * 8 + 1
-- Evaluates to: 33
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/c_test/bin
EDIT:
as far as I get from autoconf source, it does series of compile cycles with possible size values (binary search between lo and hi bounds). Event thought, still not sure how exactly it connects to proper expression execution.
EDIT2:
relevant autoconf commit and source of _AC_COMPUTE_INT

OK, giving it another shot. Dumb bruteforce in the right direction of the value using _Static_assert() from C11. Bruteforce part to be updated to proper binary search.
cmake_minimum_required(VERSION 3.5)
set(CMAKE_C_STANDARD 11)
# we need this gimmic because math(EXPR ...) does not work well with negative numbers
function (INC OUTPUT_VAR NUMBER)
if (${NUMBER} LESS 0)
math(EXPR res_var "0 ${NUMBER} + 1")
else()
math(EXPR res_var "${NUMBER} + 1")
endif()
set(${OUTPUT_VAR} ${res_var} PARENT_SCOPE)
endfunction()
function (DEC OUTPUT_VAR NUMBER)
if (${NUMBER} LESS 0)
math(EXPR res_var "0 ${NUMBER} - 1")
else()
math(EXPR res_var "${NUMBER} - 1")
endif()
set(${OUTPUT_VAR} ${res_var} PARENT_SCOPE)
endfunction()
# passing expression through pipe to C compiler instead of file.
# can be done in more portable manner, of course
function(GCC_ASSERT OUTPUT_VAR EXPRESSION)
execute_process(
COMMAND bash -c "echo '${EXPRESSION}' | ${CMAKE_C_COMPILER} -o /dev/null -xc -c -"
RESULT_VARIABLE result_var
OUTPUT_QUIET ERROR_QUIET
)
if (${result_var} EQUAL 0)
set(${OUTPUT_VAR} true PARENT_SCOPE)
else()
set(${OUTPUT_VAR} false PARENT_SCOPE)
endif()
endfunction()
function(GCC_IF_LESS OUTPUT_VAR A B)
set(C_EXPRESSION "_Static_assert(((signed int)${A}) < ((signed int)${B}), \"\")\;")
GCC_ASSERT(TEST_CON_LESS ${C_EXPRESSION})
set(${OUTPUT_VAR} ${TEST_CON_LESS} PARENT_SCOPE)
endfunction()
function(AC_COMPUTE_INT OUTPUT_VAR EXPRESSION)
set(MID_POINT 1)
# if expression evaluates to something < MID_POINT, keep decreasing it
# if expression evaluates to something > MID_POINT, keep increasing it
# if it's neither, we have the right MID_POINT which is equal to
# evaluated expression
while(true)
GCC_IF_LESS(EXPRESSION_IS_LESS ${EXPRESSION} ${MID_POINT})
GCC_IF_LESS(EXPRESSION_IS_MORE ${MID_POINT} ${EXPRESSION})
if (${EXPRESSION_IS_LESS})
DEC(MID_POINT ${MID_POINT})
elseif(${EXPRESSION_IS_MORE})
INC(MID_POINT ${MID_POINT})
else()
set(${OUTPUT_VAR} ${MID_POINT} PARENT_SCOPE)
break()
endif()
endwhile()
endfunction()
set(MY_FANCY_INPUT "sizeof(int) * 8 - 40")
AC_COMPUTE_INT(MY_FANCY_OUTPUT ${MY_FANCY_INPUT})
message(STATUS "Expression: ${MY_FANCY_INPUT}")
message(STATUS "Evaluates to: ${MY_FANCY_OUTPUT}")
Example output:
-- Expression: sizeof(int) * 8 - 40
-- Evaluates to: -8
-- Configuring done
-- Generating done

I'm not aware if there is an existing module for this.
However, here is an approach, that you can try to implement yourself. You can use execute_process to run ${CMAKE_C_COMPILER} -E on a file containing something like
// all #include's you need
xxx(YOUR_DEFINE)xxx
This would produce a file with xxx(<some_int>)xxx line. Now use CMake's file(READ and string(REGEX to pull that out.

Related

CMake: pass list of compiler flags through NVCC

I am trying to compile some CUDA and I wish to display compiler warnings. Equivalent to:
g++ fish.cpp -Wall -Wextra
Except NVCC doesn't understand these, and you have to pass them through:
nvcc fish.cu --compiler-options -Wall --compiler-options -Wextra
nvcc fish.cu --compiler-options "-Wall -Wextra"
(I favour the latter form, but ultimately, it doesn't really matter.)
Given this CMakeLists.txt (a very cut-down example):
cmake_minimum_required(VERSION 3.9)
project(test_project LANGUAGES CUDA CXX)
list(APPEND cxx_warning_flags "-Wall" "-Wextra") # ... maybe others
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options ${cxx_warning_flags}>")
add_executable(test_cuda fish.cu)
But this expands to:
nvcc "--compiler-options -Wall" -Wextra ...
which is obviously wrong. (Omitting the quotes around the generator expression just lands us in broken expansion hell.)
... skip ahead several thousand iterations of Monte Carlo programming ...
I've arrived at this gem:
set( temp ${cxx_warning_flags} )
string (REPLACE ";" " " temp "${temp}")
set( temp2 "--compiler-options \"${temp}\"" )
message( "${temp2}" )
which prints out the encouraging-looking
--compiler-options "-Wall -Wextra"
But then
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:${temp2}>")
expands to:
nvcc "--compiler-options \"-Wall -Wextra\"" ...
I'm at a loss; am I onto a dead end here? Or have I missed some crucial combination of punctuation?
I'm answering my own question, since I've found a few solutions that work, but I'm still interested to hear if there is a better (read: cleaner, more canonical) way.
TL;DR:
foreach(flag IN LISTS cxx_warning_flags)
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options=${flag}>")
endforeach()
Blow-by-blow account:
I tried this:
foreach(flag IN LISTS cxx_warning_flags)
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options ${flag}>")
endforeach()
but that still gives
nvcc "--compiler-options -Wall" "--compiler-options -Wextra"
nvcc fatal : Unknown option '-compiler-options -Wall'
Adding in a temporary however:
foreach(flag IN LISTS cxx_warning_flags)
set( temp --compiler-options ${flag}) # no quotes
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:${temp}>")
endforeach()
Gives a new outcome:
nvcc --compiler-options -Wall -Wextra ...
nvcc fatal : Unknown option 'Wextra'
What I assume is happening here is that CMake is combining the repeated --compiler-options flags, but I'm just speculating.
So, I tried eliminating the spaces using an equals:
foreach(flag IN LISTS cxx_warning_flags)
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options=${flag}>")
endforeach()
Hurrah! We have a winner:
nvcc --compiler-options=-Wall --compiler-options=-Wextra ...
Epilogue:
Can we do it without the loop?
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options=${cxx_warning_flags}>")
doesn't work (--compiler-options=-Wall -Wextra), but:
string (REPLACE ";" " " temp "${cxx_warning_flags}")
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options=${temp}>")
does work ("--compiler-options=-Wall -Wextra").
I'm slightly surprised about this last option, but I guess it makes sense. On balance, I think the looping option is clearest in its intention.
EDIT:
In Confusing flags passed to MSVC through NVCC with CMake, I spent a lot of time discovering that it might be better to use:
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=${flag}>")
since CMake appears to do some rationalisation of flags to remove duplicates and ambiguity, but does not realise that --compiler-options is the same as its favoured -Xcompiler.

Use value from C/C++ macro in CMake

What is the easiest way to get the value of a C/C++ macro into a CMake variable?
Given I check for a library libfoo with the header foo.h. I know foo.h contains the macro #define FOO_VERSION_MAJOR <version> where version is an integer or string value. To extract the major version of the found library, I want to use the value from this macro.
As a bonus, if the macro is not found, this could indicate a version older then a specific version introducing the version macro.
I'd go with file(READ ...) to read the header followed by string(REGEX ...) to extract desired define.
Example code:
file(READ "foo.h" header)
string(REGEX MATCH "#define FOO_MAJOR_VERSION [0-9]+" macrodef "${header}")
string(REGEX MATCH "[0-9]+" FooMajorVersion "${macrodef}")
With try_compile and the right pragma it is possible to output the value of a pre-processor macro during compile time. CMake can parse the output to get the desired value.
CMake snippet:
try_compile(result "${CMAKE_BINARY_DIR}"
SOURCES "${CMAKE_SOURCE_DIR}/foo-version.cpp"
OUTPUT_VARIABLE fooversion)
string(REGEX MATCH ": [0-9]+" fooversionshort "${fooversion}")
string(REGEX MATCH "[0-9]+" FooMajorVersion "${fooversionshort}")
foo-version.cpp:
#include "foo.h"
/* definition to expand macro then apply to pragma message */
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#pragma message(VALUE(FOO_MAJOR_VERSION))
int main()
{
return 0;
}
Good:
Actual value from the variable, which might be calculated.
Bad:
Output of macros is only support by some newer compilers.
Parsing of output might break for untested compilers, as the format changes from compiler version to compiler version.
Kind of complicated code, verbose code which is difficult to read.
The macro expansion can be extracted by using the C preprocessor.
I used this method to extract specific typedef's without needing to know the exact location of the define in the file hierarchy.
Let say that we have this macro defined somewhere in foo.h
#define FOO_VERSION_MAJOR 666
You need to create a helper file helper.c with this content
#include "foo.h"
int __READ_FOO_MAJOR__ = FOO_VERSION_MAJOR ;
Note that I used a specific pattern __READ_FOO_MAJOR__ that I will use later as the pattern for a grep command
And from CMakeLists.txt you have to call the C (C++, etc..) preprocessor and filter its output like this
cmake_minimum_required(VERSION 3.0)
execute_process(
COMMAND bash "-c" "${CMAKE_C_COMPILER} -E ${CMAKE_CURRENT_SOURCE_DIR}/helper.cpp | grep __READ_FOO_MAJOR__ | awk '{ print $4}'"
OUTPUT_VARIABLE FOO_VERSION_MAJOR )
message("From CMake: FOO_VERSION_MAJOR=${FOO_VERSION_MAJOR}")
Note that awk '{ print $4}' extract the 4th word on the selected line.
When running cmake we get this result
From CMake: FOO_VERSION_MAJOR=666
The short shel pipeline used is built with Unix system V base commands and should run everywhere.

CMake add_definitions does not seem to work

I'm trying to define a preprocessor variable via CMake, but unfortunately it does not seem to work.
The following is my c++ code:
#ifdef hehe_test
#define it_exists "it_exists"
#endif
#ifndef hehe_test
#define it_exists "it_doesnt_exist"
#endif
int main(int argc, char** argv)
{
printf("%s\n",it_exists);
return 0;
}
And this is my CMakeLists.txt:
project(LibraryTester)
add_definitions(hehe_test)
file(GLOB src "*.h" "*.cpp")
include_directories(${CMAKE_SOURCE_DIR}/include)
add_executable( ${PROJECT_NAME} ${src})
When i run my program it outputs: it_doesnt_exist
indicating "hehe_test" has not been defined.
What am i doing wrong here?
The following form won't do what you expect in any case:
add_definitions(hehe_test)
According to the documentation the form is:
add_definitions(-DFOO -DBAR ...)
In your case it means:
add_definitions(-Dhehe_test)
You can also give them a value if required:
// statically defined
add_definitions(-Dfoo=bar)
// use a cmake or user-defined variable
add_definitions(-Dbar=${FOO})
// use "" if you intend to pass strings with spaces
add_definitions(-Dxxx="${YYY}")
Note that you can put all of them together in the same add_definitions call.
In order to get the C/C++ effect of :
#define _MYSYMBOL
From the command line you can :
cmake . -DCMAKE_C_FLAGS=" -D_MYSYMBOL " -DCMAKE_CXX_FLAGS=" -D_MYSYMBOL "
From within CMakeLists.txt:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_MYSYMBOL")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_MYSYMBOL")
These add flags to the c/c++ compiler command directly.
-D is define symbol
You can also use cmake's add_definitions command
add_definitions ( -D_MYSYMBOL1 -D_MYSYMBOL2 )
add_definitions makes some slight assumptions as described here

Compute real number in CMake

I am using CMake to configure some scripts required to build my project using configure_file.
Some of these scripts do not have any math functionality, so I need to compute derived values in my CMake script using the math macro, e.g.:
math(EXPR EXAMPLE_BLOCK_SIZE "${EXAMPLE_SIZE} / ${EXAMPLE_BLOCK_COUNT}")
However, it seems that math does not support floating point arithmetic. If I set -DEXAMPLE_SIZE=2.5 and -DEXAMPLE_BLOCK_COUNT=2 CMake throws an error:
math cannot parse the expression: "2.5 * 2": syntax error, unexpected
exp_NUMBER, expecting $end (2)
Is there any way to compute a real number directly using CMake macros?
If not, what would be a portable way to achieve this?
First of all, floating-point math is not supported on CMake as far as I know. It is possible to compute variables, however, using shell commands. The following CMake function should do the trick:
function(floatexpr expr output)
execute_process(COMMAND awk "BEGIN {print ${expr}}" OUTPUT_VARIABLE __output)
set(${output} ${__output} PARENT_SCOPE)
endfunction()
Example usage:
set(A 2.0)
set(B 3.0)
floatexpr("${A} / ${B}" RESULT)
message(${RESULT})
NOTE: More advanced computations (such as trigonometric functions) can be computed using the command bc -l <<< 'EXPRESSION', but it's not part of the standard system packages and may not be installed.
EDIT: A completely portable (albeit much slower) solution would be to use the try_run functionality to compile a C file that runs the expression:
function(floatexpr expr output)
SET(FLOAT_EXPR_SRC "
#include <stdio.h>
int main(int argc, char *argv[]){printf(\"%f\\n\", ${expr})\; return 0\;}
")
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFloatExpr.c ${FLOAT_EXPR_SRC})
try_run(RESULT COMPRES ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/CMakeFloatExpr.c
RUN_OUTPUT_VARIABLE __output)
set(${output} ${__output} PARENT_SCOPE)
endfunction()

Using value of __GLIBCXX__ in cmake

There are plenty of examples of using cmake to set a preprocessor value. I'm having the reverse problem -- I want to find the value of __GLIBCXX__ and then perform other cmake commands conditionally based on the result.
Up until now, I had been using the GCC version as a surrogate for libstdc++ functionality, like this:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
....
# other gcc versions
....
endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# and so on
endif()
The problem I'm now having is the fallout from a known issue with libstdc++ and gcc-4.8 c++11 regex support, and the fact on many setups clang reuses the system libstdc++, therefore inheriting the same problem. Under these circumstances, there's no version test for clang that will help, since it's specifically related to libstdc++, and my surrogate method of using the compiler version no longer works.
In order to fallback on Boost.Regex or PCRE if either clang or gcc are using the libstdc++ distributed with gcc-4.8 or earlier, the best way I can think of is to check if __GLIBCXX__ <= 20140404, but I can't see how to get cmake to do it in a straight-forward way, since clang might not always be using libstdc++, e.g. most OS X systems.
CheckVariableExists doesn't seem to help, I suppose for at least two reasons; firstly, a preprocessor macro isn't a variable, and secondly, it doesn't give the value, only indicates its presence.
You could use CHECK_CXX_SOURCE_COMPILES to compile a specific test which fails when your condition is not met:
INCLUDE (CheckCXXSourceCompiles)
CHECK_CXX_SOURCE_COMPILES(
"
#include <cstdio>
#ifdef __GLIBCXX__
#if __GLIBCXX__ <= 20140404
#error test failed
#endif
#endif
int main() { return 0;}
" GLIBCXX_TEST)
IF(NOT GLIBCXX_TEST)
MESSAGE(STATUS "__GLIBCXX__ test failed")
ENDIF()
Based on m.s.'s idea and taking Marc Glisse's observation about __GLIBCXX__ not being a reliable way to test for this, I wrote a CMake module to test for broken implementations of regex support. In order for this test to pass, the compiler will need to be targetting C++11 or higher.
Gist is here: https://gist.github.com/anonymous/7520ce6f64c63e2f8e79
Sample use:
include(CheckForRegex)
check_cxx_native_regex_works(USE_NATIVE_REGEX)
add_definitions("-DUSE_NATIVE_REGEX=${USE_NATIVE_REGEX}")
if (NOT USE_NATIVE_REGEX)
find_package(Boost REQUIRED COMPONENTS regex)
endif()