Search code examples
cmakeprocessorfpic

Detect 32-bit x86 processor in CMakeList.txt?


We are catching errors in our CMake makefiles due to lack of -fPIC. Her's one from a ci20 MIPS dev-board:

...
[ 92%] Built target cryptopp-object
Scanning dependencies of target cryptopp-shared
Scanning dependencies of target cryptopp-static
Linking CXX static library libcryptopp.a
Linking CXX shared library libcryptopp.so
/usr/bin/ld: CMakeFiles/cryptopp-object.dir/cryptlib.cpp.o: relocation R_MIPS_HI16 against
`a local symbol' can not be used when making a shared object; recompile with -fPIC
CMakeFiles/cryptopp-object.dir/cryptlib.cpp.o: could not read symbols: Bad value
collect2: ld returned 1 exit status

The project's policy is to us PIC everywhere except 32-bit x86 due to register pressures. That means x86_64, ARM-32, Aarch32, Aarch64, MIPS, MIPS64, UltraSparc, etc get PIC.

I believe the target processor is provided in CMAKE_SYSTEM_PROCESSOR. The problem I am having is the docs don't tell me the values, so I can't figure out how to craft a "not 32-bit x86" test.

How do I detect 32-bit x86 processor in CMakeList.txt?

Even better, I would like to see a comprehensive list of processors that CMake sets CMAKE_SYSTEM_PROCESSOR to. If anyone has the list, then it would be great to provide it.


Solution

  • I probably would build something around the compiler.

    A close approximation using existing variables/modules would be:

    include(TestBigEndian)
    
    if (NOT WIN32)
        TEST_BIG_ENDIAN(_bigendian)
        if((CMAKE_SIZEOF_VOID_P GREATER 4) OR (_bigendian))
            message(
                STATUS "Setting ${CMAKE_CXX_COMPILE_OPTIONS_PIC} "
                       "for machine ${CMAKE_HOST_SYSTEM_PROCESSOR}"
            )
            set(CMAKE_POSITION_INDEPENDENT_CODE 1)
        endif()
    endif()
    

    In short what I have done:

    • WIN32 is also valid for 64 Bit Windows compilers/environments
    • CMAKE_SIZEOF_VOID_P GREATER 4 checks for "greater then 32 Bit"
    • The last is the biggest assumption: take all little endian processors as Intel/AMD based
    • Used more generic CMAKE_POSITION_INDEPENDENT_CODE to set -fPIC

    I admit a more accurate method would be to build something around a pre-defined macros test.

    Edit: Added "Predefined Macros Check" Alternative

    Here is the more precise check for predefined macros:

    include(CheckCXXSourceCompiles)
    
    if (CMAKE_CXX_COMPILE_OPTIONS_PIC)
        set(
            _preDefMacrosX86 
                __i386 __i386__ __i486__ __i586__ __i686__      
                _M_I86 _M_IX86 __X86__ _X86_ __THW_INTEL__
                __I86__ __INTEL__ __386
        )
        set(_code "void main() {}")
        foreach(_macro IN LISTS _preDefMacrosX86)
            set(
                _code
                "${_code}\n\#ifdef ${_macro}\n\#error ${_macro} is defined\n\#endif"
            )
        endforeach()
        CHECK_CXX_SOURCE_COMPILES("${_code}" _canCompileX86DoesFailCheck)
    
        if((CMAKE_SIZEOF_VOID_P GREATER 4) OR (_canCompileX86DoesFailCheck))
            message(STATUS "Setting ${CMAKE_CXX_COMPILE_OPTIONS_PIC}")
            set(CMAKE_POSITION_INDEPENDENT_CODE 1)
        endif()
    endif()
    

    References