How can I make Cmake use specific compiler and flags when final compilation stage instead of detection?
I solved this and built Bullet Physics for iOS.
Solution
Here's toolchain configuration that I used.
INCLUDE(CMakeForceCompiler)
SET (CMAKE_CROSSCOMPILING TRUE)
SET (CMAKE_SYSTEM_NAME "Darwin")
SET (CMAKE_SYSTEM_PROCESSOR "arm")
SET (SDKVER "4.3")
SET (DEVROOT "/Developer/Platforms/iPhoneOS.platform/Developer")
SET (SDKROOT "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${SDKVER}.sdk")
SET (CC "${DEVROOT}/usr/bin/clang")
SET (CXX "${DEVROOT}/usr/bin/clang++")
CMAKE_FORCE_C_COMPILER (${CC} CLang)
CMAKE_FORCE_CXX_COMPILER (${CXX} CLang)
SET (CMAKE_FIND_ROOT_PATH "${SDKROOT}" "${DEVROOT}")
SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
And the build script. This is important!
PKG_NAME=bullet-2.78
BUILD_DIR=build
rm -rf ${PKG_NAME} ${BUILD_DIR}
tar -x -f ${PKG_NAME}-r2387.tar
mkdir build
cd build
DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
SYSROOT=$DEVROOT/SDKs/iPhoneOS4.3.sdk
CC=$DEVROOT/usr/bin/clang
CXX=$DEVROOT/usr/bin/clang++
CFLAGS="-arch armv6 -arch armv7 -isysroot $SYSROOT -miphoneos-version-min=4.0"
CXXFLAGS=$CFLAGS
LDFLAGS=$CFLAGS
export CC=$CC
export CXX=$CXX
export CFLAGS=$CFLAGS
export CXXFLAGS=$CXXFLAGS
export LDFLAGS=$LDFLAGS
cmake ../$PKG_NAME -DCMAKE_TOOLCHAIN_FILE=../CMAKE_IPHONEOS_TOOLCHAIN.cmake
make
lipo -info src/LinearMath/libLinearMath.a
This is very minimal configuration. However you got the idea.
Description
First, the toolchain configuration is just a stage figuring out features available on target machine. But cross compilation to iOS require some special compiler flags, and this is exception situation described on Cmake wiki.
So I just forced specific compiler, and Cmake will skip compiler verification stage.
Second, all compiler flags needed for cross compilation offered via shell variable export in build script. This is very rough options, however important is we have to pass via shell variables. Not with toolchain configuration.
However some kind of toolchain configuration affects on generated Makefile
. We have to specify correct CMAKE_SYSTEM_NAME
(Darwin
) and CMAKE_SYSTEM_PROCESSOR
(arm
).
Update
There is another trials. Anyway these don't work for me anymore.
- http://code.google.com/p/ios-cmake/
- http://www.ltengsoft.com/node/20
Here's one more. This looks promising.
- http://immersedcode.org/2011/4/25/sdl-on-ios/
Update 2
Now Bullet includes a build script for iOS platforms. Anyway it's inconvenient because it does not handle special needs for simulator stuffs, and I wrote another build script which makes far library for debug/release mode.
https://github.com/Eonil/Bullet-PhysicsEngine-BuildScript
CMAKE: how to set the compiler flags that contains a given destination path and file name
The simple method is to set the property COMPILE_OPTIONS
for each needed source file.
Here is the test CMakeLists.txt
project(TestSourceProp)
set(SOURCE_FILES
main.c
file.c
)
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
foreach(SRC_ IN LISTS SOURCE_FILES)
get_filename_component(SRC_BASENAME_ ${SRC_} NAME_WE)
set_source_files_properties(${SRC_} PROPERTIES COMPILE_OPTIONS "--omf_browse=${SRC_BASENAME_}.crf;--depend=${SRC_BASENAME_}.d")
get_source_file_property(SRC_PROP_ ${SRC_} COMPILE_OPTIONS)
message(STATUS "${SRC_}: ${SRC_PROP_}")
endforeach()
The output:
...
-- main.c: --omf_browse=main.crf;--depend=main.d
-- file.c: --omf_browse=file.crf;--depend=file.d
-- Configuring done
Makefile:
CMakeFiles/TestSourceProp.dir/main.c.obj: ../main.c
@$(CMAKE_COMMAND) -E cmake_echo_color ...
gcc $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) --omf_browse=main.crf --depend=main.d -o CMakeFiles/TestSourceProp.dir/main.c.obj -c ...
Another way, I think, is to create a custom CMake-toolchain file.
CMake: add compiler flags to a target if another specific target depends on it
In CMake you cannot set compiler flags depending on what is being built.
All flags are determined on *configuration stage (cmake
invocation), but selecting targets for build is performed only on build stage (make
invocation).
While build-dependent flags are supported by make
, they are not supported by many of other build tools. And CMake tends to be build tool-independent.
How to specify a compiler in CMake?
To select a specific compiler, you have several solutions, as exaplained in CMake wiki:
Method 1: use environment variables
For C and C++, set the CC
and CXX
environment variables. This method is not guaranteed to work for all generators. (Specifically, if you are trying to set Xcode's GCC_VERSION
, this method confuses Xcode.)
For example:
CC=gcc-4.2 CXX=/usr/bin/g++-4.2 cmake -G "Your Generator" path/to/your/source
Method 2: use cmake -D
Set the appropriate CMAKE_FOO_COMPILER
variable(s) to a valid compiler name or full path on the command-line using cmake -D
.
For example:
cmake -G "Your Generator" -D CMAKE_C_COMPILER=gcc-4.2 -D CMAKE_CXX_COMPILER=g++-4.2 path/to/your/source
Method 3 (avoid): use set()
Set the appropriate CMAKE_FOO_COMPILER
variable(s) to a valid compiler name or full path in a list file using set()
. This must be done before any language is set (ie: before any project()
or enable_language()
command).
For example:
set(CMAKE_C_COMPILER "gcc-4.2")
set(CMAKE_CXX_COMPILER "/usr/bin/g++-4.2")
project("YourProjectName")
The wiki doesn't provide reason why 3rd method should be avoided...
How can you add warning flags using cmake cross platform?
It relies on you having, for every project, to add specific support for each >compiler that you support, one at a time.
At now you can only have something like compiler.cmake
, where you configure suitable flags for each compiler, and share compiler.cmake
among projects.
Is there no equivalent solution for adding the equivalent of -Wall / /W3 to the >compile simply via a cmake setting?
No, now there is only disscussion about similar feature and it's possible implementation, see
https://cmake.org/pipermail/cmake-developers/2016-March/028107.html
How do I detect that I am cross-compiling in CMakeLists.txt?
The test for CMAKE_CROSSCOMPILING must come after the "project" instruction in CMakeLists.txt.
How to instruct CMake to use the build architecture compiler
CMake can only handle one compiler at a time. So - if you don't go the long way to set up the other compiler as a new language - you will end up with two configuration cycles.
I see the following approaches to automate this process:
Taking the example "CMake Cross Compiling - Using executables in the build created during the build?" from the CMake pages as a starting point I'll get:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# When crosscompiling import the executable targets
if (CMAKE_CROSSCOMPILING)
set(IMPORT_PATH "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point it to the export file path from a native build")
file(TO_CMAKE_PATH "${IMPORT_PATH}" IMPORT_PATH_CMAKE)
include(${IMPORT_PATH_CMAKE}/genfooTargets.cmake)
# Then use the target name as COMMAND, CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
endif()
# Only build the generator if not crosscompiling
if (NOT CMAKE_CROSSCOMPILING)
add_executable(genfoo genfoo.cpp)
export(TARGETS genfoo FILE "${CMAKE_CURRENT_BINARY_DIR}/genfooTargets.cmake")
endif()Then using a script like:
build.sh
#!/bin/bash
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ..
fi
cmake --build hostBuild
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DIMPORT_PATH=${PWD}/hostBuild -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
cmake --build crossBuildI'll get the desired results by calling
./build.sh
.Splitting the
CMakeLists.txt
and maybe even replace theexport()
/include()
with something where I know the output path of my build tools e.g. by usingCMAKE_RUNTIME_OUTPUT_DIRECTORY
would simplify things:CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# Then use the target name as COMMAND. CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})buildTools/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(BuildTools)
add_executable(genfoo genfoo.cpp)build.sh
#!/bin/bash
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ../buildTools -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${PWD}/crossBuild
fi
cmake --build hostBuild
cmake --build crossBuild
References
- Making a CMake library accessible by other CMake packages automatically
- CMake build multiple targets in different build directories
- How do I make CMake output into a 'bin' dir?
Override compile flags for single files
Your attempts above are adding further flags to your file/target rather than overwriting as you seem to expect. For example, from the docs for Properties on Source Files - COMPILE_FLAGS:
These flags will be added to the list of compile flags when this source file builds.
You should be able to countermand the -Weffc++
flag for foo.cpp by doing
set_source_files_properties(foo.cpp PROPERTIES COMPILE_FLAGS -Wno-effc++)
This should have the effect of adding -Wno-effc++
after -Weffc++
in the compiler command, and the latter setting wins. To see the full command and check that this is indeed the case, you can do
make VERBOSE=1
As an aside, one of the maintainers of the GNU C++ Standard Library presents a pretty negative opinion on -Weffc++
in this answer.
Another point is that you're misusing add_definitions
in the sense that you're using this for compiler flags rather than the intended preprocessor definitions.
It would be preferable to use add_compile_options
add_compile_options(-Wall -Weffc++ -pedantic -std=c++0x)
or for CMake versions < 3.0 to do something more like:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Weffc++ -pedantic -std=c++0x")
In response to further questions in the comments below, I believe it's impossible to reliably remove a flag on a single file. The reason is that for any given source file, it has the COMPILE_OPTIONS
and COMPILE_FLAGS
1 of its target applied, but these don't show up in any of the properties for that source file.
You could look at stripping the problem flag from the target's COMPILE_OPTIONS
, then applying it to each of the target's sources individually, omitting it from the specific source file as required.
However, while this could work in many scenarios, it has a couple of problems.
First - source files' properties don't include COMPILE_OPTIONS
, only COMPILE_FLAGS
. This is a problem because the COMPILE_OPTIONS
of a target can include generator expressions, but COMPILE_FLAGS
doesn't support them. So you'd have to accommodate generator expressions while searching for your flag, and indeed you'd maybe even have to "parse" generator expressions if your flag was contained in one or more to see whether it should be re-applied to the remaining source files.
Second - since CMake v3.0, targets can specify INTERFACE_COMPILE_OPTIONS
. This means that a dependency of your target can add or override your target's COMPILE_OPTIONS
via its INTERFACE_COMPILE_OPTIONS
. So you'd further have to recursively iterate through all your target's dependencies (not a particularly easy task since the list of LINK_LIBRARIES
for the target can also contain generator expressions) to find any which are applying the problem flag, and try and remove it from those targets' INTERFACE_COMPILE_OPTIONS
too.
At this stage of complexity, I'd be looking to submit a patch to CMake to provide the functionality to remove a specific flag unconditionally from a source file.
1: Note that unlike the COMPILE_FLAGS
property on source files, the COMPILE_FLAGS
property on targets is deprecated.
Related Topics
Uitableview Add Cell Animation
Xcode Instruments Allocations: Look at Live Bytes or Overall Bytes
iOS Floating Video Window Like Youtube App
How to Update Uibutton Title/Text Programmatically
iOS 9 Searchbar Disappears from Table Header View When Uisearchcontroller Is Active
How to Add Textfield to Uialertcontroller in Swift
Nspredicate to Test for Null, and Blank Strings
How to Get the Hour of the Day with Swift
Conflicting Return Type in Implementation of 'Supportedinterfaceorientations': - Warning
Xcode 6 Beta 7: Storyboard Adds Extra Space on Right and Left Sides
Undefined Symbols for Architecture Armv7 When Using Zxing Library in Xcode 4.5
Waiting for Asynchronous Function Call to Complete
Uitableviewcell Separator Disappearing in iOS7
How to Change Height of Uitableviewcell Real-Time