Detect 32-bit x86 processor in CMakeList.txt?
Asked Answered
J

2

2

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.

Janycejanyte answered 14/9, 2016 at 3:42 Comment(0)
D
1

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

Dank answered 14/9, 2016 at 21:18 Comment(3)
Thanks again Florian. I did not know about CMAKE_POSITION_INDEPENDENT_CODE . I'll get it added.Janycejanyte
" ...take all little endian processors as Intel based" - That may need to be loosened up a bit. All ARM processors I work with are LE. The corner case might be a PowerPC found in say, old Apple G5's. Its BE, and it needs -fPIC (IIRC). I have one of those G5's in my basement for testing BE builds of the library. When Verizon fixes port forwarding in their routers, I can give you remote SSH access if you want it. PF used to work, but VZ broke it in the 4XX series firmware ror updates. You can test CMake all you like :)Janycejanyte
@Janycejanyte Yeah, I should have known better. Sorry for that. I've added the much more precise "check for predefined x86 macros" version. That should do it.Dank
J
0

I believe this performs the detection on nearly everything except Windows. Windows does not consume -fPIC, so it does not matter to me. The pieces were glued together from three Stack Overflow answers.

# Stop hiding the damn output...
set(CMAKE_VERBOSE_MAKEFILE on)

# Enable PIC for all targets except Windows and 32-bit x86
if (NOT (WINDOWS OR WINDOWS_STORE OR WINDOWS_PHONE))

    set (UNAME_CMD "uname")
    set (UNAME_ARG "-m")
    execute_process(COMMAND ${UNAME_CMD} ${UNAME_ARG}
        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
        RESULT_VARIABLE UNAME_RESULT
        OUTPUT_VARIABLE UNAME_MACHINE)

    # Use Regex; match i386, i486, i586 and i686
    IF (NOT (${UNAME_MACHINE} MATCHES "i.86"))
        # message(STATUS "Setting -fPIC for machine ${UNAME_MACHINE}")
        if (CMAKE_VERSION VERSION_LESS 2.8.12)
            add_definitions(-fPIC)
        else()
            add_compile_options(-fPIC)
        endif()
    endif()
endif()

You get the machine with uname -m, and its mostly accurate, even on OS X. For example, on OS X, uname -p returns i386 while uname -m returns x86_64. I seem to recall 10.6 or 10.7 was a little flaky as the transition was being made to 64-bit Macs.

You get the processor with uname -p sometimes, but it fails on many dev-boards. For example my ci20 dev-board returns "mips" for the machine and "unknown" for the processor. Another example is my LeMaker HiKey. It returns "aarch64" for the machine and "unknown" for the processor.


I'd still like to see the list of processors provided by Cmake.

Janycejanyte answered 14/9, 2016 at 5:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.