I am new to cmake. I want to build my project for x86 and arm architectures (on x64 machine). I setup two toolchain files: x86.cmake and arm.cmake, with paths to compilers.
My project uses my own pre-compiled libraries which lay in different paths for x86 and arm. So the question is how do I link these libraries depending on target architecture?
The way I see now is set set(CMAKE_SYSTEM_PROCESSOR arm) in arm.cmake toolchain and
set(CMAKE_SYSTEM_PROCESSOR x86) for x86.cmake toolchain and then depending on this variable choose the right paths of libraries.
Is this the right way?
Usually libraries needed for link with are searched with find_library command. This command uses several hints which could be set in the toolchain file. E.g.:
CMAKE_SYSROOT variable
CMAKE_FIND_ROOT_PATH variable
So, result of find_library could be different for different toolchains in use.
Related
Our project builds with CMake on several platforms, including Windows, Linux and cross-compilation on some embedded OSes, described with custom CMake toolchain files.
In case of cross-compilation, we have to maintain sets of preprocessor macros.
It is reflected in CMakeLists.txt in the following fashion.
File embedded_os1.toolchain.cmake
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR ARM)
set(CMAKE_C_COMPILER /path/to/cross-compiler)
# blah-blah-blah
set(embedded_OS1 TRUE)
... and we have similar files for other embedded OSes.
File CMakeLists.txt
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
if(embedded_OS1)
add_definitions(-Dmacro1 -Dmacro2)
elseif(embedded_OS2)
add_definitions(-Dmacro3 -Dmacro4)
elseif(embedded_OS3)
add_definitions(-Dmacro1 -Dmacro4)
endif()
I'd like to perform some kind of automatic checking that all preprocessor macros are set correctly.
I can easily do it with unit-tests on Windows and Linux.
But there is no possibility to compile and run executable files on embedded OSes, I can compile only static libs, that are then signed, put in a firmware images, etc, etc. And all I have on PC besides library is the JSON file with compiler calls, generated by EXPORT_COMPILE_COMMANDS.
What could you suggest?
I'd do it with #warning macro and check the compilation output with bash of whatever. Then you can set Werror for these files and get compile-time check. Or simply use #error (thanks to KamilCuk)
Another way is to dig into check binaries that help to see if the toolchain has threading or something else.
I have a general question that stems from a more specific issue I'm having with cross-compiling for aarch64/ARMv8.
First, my specific issue is that I can't seem to get my arm toolchain's ld binary to link against glibc/libc objects.
example_path/aarch64-linux-gnu/bin/ld: cannot find crt1.o: No such file or directory
I suppose that because it is an .o, I should probably use the one from my target platform instead of my host one. So I have copied sysroot from my target platform (no bin, just /usr/include and /usr/lib), and I have added that into a directory in my workspace called aarch64. Now, in my toolchain.cmake file, I've set this, because I don't want to use an x86-64 libs or headers:
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_SYSROOT /usr/bin/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu)
Because CMAKE_FIND_ROOT_PATH_MODE_LIBRARY is sent to ONLY, CMake should ignore usual library paths.
So this has led to my general question:
What is the best/most-commonly accepted way to structure directories etc for cross-compiling? Obviously, I don't want to put my target's sysroot in /usr/... but I need to be able to link against the ARM sysroot for all the libs installed there. Is it as simple as using:
link_directories(...)
in the toolchain file?
Where do people usually store the sysroot?
Thanks for your time, and apologies if this is a simple question - I am new to cross-compiling.
I have a CMake project that supports multiple platform combination (arm, powerpc ,x86-64). Native platform is x86-64.
I have toolchain.cmake file for each cross-platform build(for arm and powerpc).
When I give toolcahin.cmake files for cross-platform build to cmake everything is working as expected except one thing.
In the project I want to build a particular executable with native build support(that is on x86-64). Since I gave toolchain.cmake file explicitly, so all CMAKE_C_FLAGS are global for all executable in project.
So I want to give toolchain.cmake(say for arm) to cmake and want to build the whole project except one executable on native(x86-64) in one go.
Is there any way where I can change the complete CMAKE_C_FLAGS and can provide the native one for that particular executable ?
I tried few things as per How to change a compiler flag for just one executable in CMake? but can't get the solution to this problem
I am using a standalone toolchain made from the android ndk13b. It works fine, but to find all the tools (linker, archiver etc.) I have a quite verbose section in my toolchain file. Is there a way to make it more condensed?
SET(COMPILER_PATH "<path_to_my_llvm_directory>")
SET(CMAKE_TOOLCHAIN_PREFIX aarch64-linux-android-) #In theory should allow to find minor tools like ar and objdump, see http://stackoverflow.com/a/7032021/2436175
find_program(CMAKE_C_COMPILER clang.cmd PATH ${COMPILER_PATH})
find_program(CMAKE_CXX_COMPILER clang++.cmd PATH ${COMPILER_PATH})
find_program(CMAKE_AR ${CMAKE_TOOLCHAIN_PREFIX}ar.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_RANLIB ${CMAKE_TOOLCHAIN_PREFIX}ranlib.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_LINKER ${CMAKE_TOOLCHAIN_PREFIX}ld.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_NM ${CMAKE_TOOLCHAIN_PREFIX}nm.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_OBJCOPY ${CMAKE_TOOLCHAIN_PREFIX}objcopy.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_OBJDUMP ${CMAKE_TOOLCHAIN_PREFIX}objdump.exe PATHS ${COMPILER_PATH})
find_program(CMAKE_STRIP ${CMAKE_TOOLCHAIN_PREFIX}strip.exe PATHS ${COMPILER_PATH})
What didn't work:
Not explicitly using find_program -> It finds some other tools from some other mingw toolchain I have in my path
Setting CMAKE_FIND_ROOT_PATH to ${COMPILER_PATH}. It won't even find the compiler at that point. I can workaround that by setting the compiler instead with SET(CMAKE_C_COMPILER ${COMPILER_PATH}/clang.cmd) (same for clang++), but it still doesn't find the other tools
Trying various flags with find_program, especially ONLY_CMAKE_FIND_ROOT_PATH
Note that I found find_program to be the only workaround to find the tools, because for example the following won't work:
SET(CMAKE_AR ${COMPILER_PATH}/${CMAKE_TOOLCHAIN_PREFIX}ar.exe
(The archive operation will fail and I can see from cmake-gui that the variable is not set).
The good new is that Android NDK support got a lot easier with the latest CMake 3.7 release. See Kitware Increases Android Support in CMake 3.7 and Cross Compiling for Android.
Edit: I have successfully run a test with CMake 3.7 (e.g. installed ADK to root on my Windows PC):
toolchain.cmake
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSROOT "C:/android-ndk-r13b/platforms/android-24/arch-arm64")
And used e.g. the Ninja makefile generator:
> cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -G "Ninja" ..
-- Android: Targeting API '24' with architecture 'arm64', ABI 'arm64-v8a', and processor 'aarch64'
-- Android: Selected GCC toolchain 'aarch64-linux-android-4.9'
-- The C compiler identification is GNU 4.9.0
-- The CXX compiler identification is GNU 4.9.0
Simplified Toolchains in General
I've made some good experiences with minimal toolchain files and generally - if you want to specify tool paths specifically - using cached variables in the toolchain file.
See this minimal example from CMake's documentation, which would translate in your case into something like:
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER <path_to_my_llvm_directory>/clang.cmd)
set(CMAKE_C_COMPILER_TARGET aarch64-linux-android)
set(CMAKE_CXX_COMPILER <path_to_my_llvm_directory>/clang++.cmd)
set(CMAKE_CXX_COMPILER_TARGET aarch64-linux-android)
Note that specifying CMAKE_SYSTEM_NAME is essential to enable crosscompiling.
Why specifying CMAKE_AR didn't work
Regarding your CMAKE_AR problem please note that CMake itself does use find_program() to find ar.exe. Since find_program() does cache its results, you have to prefill CMAKE_AR also as cached variable (see 0013038: cannot set CMAKE_AR when cross-compiling Fortran-only project).
I'm cross-compiling a C++ (and some C) project from Linux using Mingw-w64 (really using the MXE project), using cmake as the build system. I have come to realise that I need to either provide the dlls libstdc++ and libstdc with the resulting libraries and exe files, or staticly link to these libraries.
My questions are therefore:
Which option is preferable, static linking or supplying the files? Personally I prefer the idea of static linking, as it is simpler for the end user in my case.
Where can I find the required dlls to supply them if I wanted to (or what steps to create them). I can only find .a versions in my toolchain.
How can I instruct cmake to statically link the libraries, bearing in mind that this is only desired for the cross-compile. As a starter, see the toolchain file provided by MXE below, which is what I'm currently using. I would probably not like to modify this, but rather the CMakeLists.txt files, or via a command line cmake option for my release script.
toolchain file
set(CMAKE_SYSTEM_NAME Windows)
set(MSYS 1)
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_FIND_ROOT_PATH /opt/mxe/usr/x86_64-w64-mingw32)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_C_COMPILER /opt/mxe/usr/bin/x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER /opt/mxe/usr/bin/x86_64-w64-mingw32-g++)
set(CMAKE_Fortran_COMPILER /opt/mxe/usr/bin/x86_64-w64-mingw32-gfortran)
set(CMAKE_RC_COMPILER /opt/mxe/usr/bin/x86_64-w64-mingw32-windres)
set(HDF5_C_COMPILER_EXECUTABLE /opt/mxe/usr/bin/x86_64-w64-mingw32-h5cc)
set(HDF5_CXX_COMPILER_EXECUTABLE /opt/mxe/usr/bin/x86_64-w64-mingw32-h5c++)
set(PKG_CONFIG_EXECUTABLE /opt/mxe/usr/bin/x86_64-w64-mingw32-pkg-config)
set(QT_QMAKE_EXECUTABLE /opt/mxe/usr/x86_64-w64-mingw32/qt/bin/qmake)
set(CMAKE_INSTALL_PREFIX /opt/mxe/usr/x86_64-w64-mingw32 CACHE PATH "Installation Prefix")
set(CMAKE_BUILD_TYPE Release CACHE STRING "Debug|Release|RelWithDebInfo|MinSizeRel")
Incidentally, I have tried the following cmake invocation, but this made no difference to the binary sizes, so I assumed it didn't work. Tips on actually testing this are welcome, I do have wine installed.
cmake -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} "-static -static-libgcc -static-libstdc++"" \
-DCMAKE_TOOLCHAIN_FILE=/opt/mxe/usr/x86_64-w64-mingw32/share/cmake/mxe-conf.cmake $WORKING_COPY_DIR/release/xfemm_mingw_win64/cfemm