Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is AC_COMPUTE_INT for 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.
like image 537
Helmut Grohne Avatar asked Sep 10 '25 13:09

Helmut Grohne


1 Answers

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

like image 71
Kamiccolo Avatar answered Sep 13 '25 03:09

Kamiccolo