CMake: generate and compile architecture-specific source files in XCode - xcode

I have a CMake project that's used to generate an iOS-targeted XCode project that supports multiple CPU architectures (arm64 and armv7).
My CMake project includes some commands (defined with add_custom_command) that convert Lua scripts into C++ source files. These generated C++ files differ by architecture (the armv7 file should not be compiled for arm64 and vice versa).
The tool meant to be invoked like this:
./data_tool --input <script> --output <C++ source> --architecture <armv7 or arm64>
My (incorrect) CMake file currently looks something like this:
foreach(ARCHITECTURE ${TARGET_ARCHITECTURES})
string(
REPLACE ".lua" ".cpp" GENERATED_CPP
${GENERATED_SOURCE_DIRECTORY}/${ARCHITECTURE}/${INPUT_SCRIPT}
)
add_custom_command(
OUTPUT ${GENERATED_CPP}
COMMAND ${DATA_TOOL} --input "${INPUT_SCRIPT}" --output "${GENERATED_CPP}" --architecture ${ARCHITECTURE}
MAIN_DEPENDENCY ${INPUT_SCRIPT}
)
list( APPEND GENERATED_SOURCE ${GENERATED_CPP} )
endforeach()
Later, GENERATED_SOURCE is appended to the source file list passed to add_executable. This code is obviously wrong because both the armv7 and arm64 files are compiled when building for either architecture.
How can I tell CMake that each architecture compiles a different set of source files?

XCode doesn't have a great way to exclude files based on the architecture being built. While it is possible (see Disabling some files in XCode project from compilation), setting this up via CMake is going to be somewhat difficult.
Instead, I would suggest simply making your generation tool/script put preprocessor guards around the entire file, for the architecture that the generated file supports. That way, when XCode compiles them, they will be essentially empty, except for the architecture that they are meant for. In this answer (Determine if the device is ARM64), it shows how you can do a conditional compile based on arm64 (and use the reverse for armv7).

Well, don't put generated sources for different arches into the same list. Unwrap foreach body and just repeat these commands for each arch.
If you don't want to introduce code duplication, you can write a CMake function that creates that custom command and returns a list of generated sources. See this question for how to return values from functions.

Related

CMake + Xcode: how to select arm64 vs x86_64 libraries?

We have a CMake based project targeting Xcode, and must include a precompiled 3rd party library which supplies separate arm64 and x86_64 binaries.
What we have working now is to simply attach both binaries like
add_library( someLib INTERFACE )
add_library( someLib_x64 STATIC IMPORTED )
set_target_properties(
someLib_x64
PROPERTIES
IMPORTED_LOCATION_RELEASE "path/to/x64/libsomeLib.a"
)
add_library( someLib_arm STATIC IMPORTED )
set_target_properties(
someLib_arm
PROPERTIES
IMPORTED_LOCATION_RELEASE "path/to/arm/libsomeLib.a"
)
target_link_libraries(
someLib
INTERFACE
someLib_x64
someLib_arm
)
This seems to result in a valid compilation for both architectures (building for "Any Mac (Apple Silicon, Intel)"), however it causes a bunch of linker warnings as each architecture complains about the other one.
ld: warning: ignoring file /path/to/x64/libsomeLib.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
and vice versa.
What is a more accurate way to do this that avoids linker warnings? I couldn't find an applicable generator expression to change the link path?
Edited, I misunderstood this previously. I think you have 3 options
suppress error, the error doesn't affect anything in fact, so the simplist way to
add_link_option("-w")
to ignore it, or just change link option for the target
try the latest cmake concept IMPORTED_TARGET, it looks like perfectly fit your demand, but require new cmake version
try to compile an universal library from source code, this is some example
change flag or cmake official example, but this looks like need another project for source code of the lib
UPDATE: ACCEPTED ANSWER:
Based on the documentation for IMPORTED_TARGET linked here, it revealed that you can use the symbol $(CURRENT_ARCH) in the library path, which is interpreted by Xcode at link time.
Works perfectly.
You can combine the two .a files into the fat binary and use the combined library for compilation. The linker will select the correct version based on the architecture.
To combine the .a library files, you can use the lipo command:
lipo -create 'path/to/x64/libsomeLib.a' 'path/to/arm/libsomeLib.a' \
-output 'path/to/combined/libsomeLib.a'
The combined library file can be reused until you need to install an update to the library. Alternatively, you can create a aggregate target to combine the library files every time you compile if you prefer not to manage the library manually.

Generate list files with CMake

I hope this is a simple question and I'm just missing something fundamental.
I'm trying to emulate a binary build manager for an embedded Cortex-M0 target using a CMake project. I'm having some trouble figuring out how to generate list files for each dependency of my executable target.
The current build system, when building a file called main.c passes -Wa,-alh=.\CortexM0\ARM_GCC_493\Debug/main.lst as an argument to gcc. I can't figure out how to get CMake to use the current filename without the extension to save the file.
I've looked at the get_filename_component command, but it appears only to get the filename of the output:
add_executable(TestExe main.c)
get_filename_component(curr_name TestExe NAME_WM)
message(${curr_name})
As expected, this prints TestExe instead of the hoped for main
Is there a simple variable I'm overlooking that I could put in my toolchain file's CMAKE_C_FLAGS like -Wa,-alh=${CURR_SOURCE}.lst? Or some other method that I'm not seeing?
System info:
Windows 10
Msys shell
CMake 3.7.2
arm-none-eabi-gcc v4.9.3
You can use Expansion Rules and extend CMAKE_C_COMPILE_OBJECT:
set(CMAKE_C_COMPILE_OBJECT "${CMAKE_C_COMPILE_OBJECT} -Wa,-alh=<OBJECT>.lst")
But there is unfortunately
no Expansion Rule that does give the current source file without path and extension
so you will get in the above example main.c.o.lst as an output name
Footnote: In CMake generated makefile projects, if you just need the assembly file can just do make main.s or for the pre-processed file make main.i.

Using CMake to resolve #include dependencies in an exotic language

I'm trying to use CMake as my build tool driver (I make it clear at once that I'm quite new to CMake since this my first on-my-own CMake project). My project is mainly C with some files in an exotic language I'll call here Z. These Z files must be processed by their Z compiler to produce .h and .c files.
I managed to tweak CMake handle Z compiling and dependencies between plain C files and generated Z -> .h header with
add_custom_command( ...*details omitted*... )
set_source_file_properties(*generated-.h* PROPERTIES GENERATED TRUE)
and CMake C-#include scanner does properly the rest of the job.
Now, Z files use something equivalent to C #include construct and I'd like to make profit of automatic recompilation when one of the Z-included files changes.
If a.Z includes inc.Z, I tried:
set_source_file_properties(a.Z PROPERTIES OBJECT_DEPENDS inc.Z)
but that doesn't trigger automatic recompilation of a.Z.
CMake manual says this property was introduced for this purpose and is no longer necessary for C/C++. However it is ineffective in my Z case.
If I modify my custom command as follows:
add_custom_command( ... DEPENDS inc.Z ...)
I get the desired result, but not all Z files depend on inc.Z (another one might depend on inc2.Z).
I then tried to generate dynamically the DEPENDS list with
get_source_file_property(dependencies ${filename} OBJECT_DEPENDS)
if(dependencies STREQUAL "NOTFOUND")
unset(dependencies)
else()
string(REPLACE ";" " " dependencies "${dependencies}")
endif()
add_custom_command(... DEPENDS $filename "$dependencies" ...)
and make errors out with
Make[2]: *** no rules to build target `-- content of dependencies variable --'
Note: error is the same with or without double quotes around variable substitution
I guess CMake interpreted my list of dependencies as a single (non-existent) filename and make was unable to handle that. Anyway, the files mentionned in the dependencies variable are not meant to be compiled, only to be included somewhere. They must make their way to make only as dependencies.
Which direction should I go to achieve the desired result?
Recall this is my first on-my-own CMake project and I certainly made newbie errors.
FWIW, my platform is Linux with CMake 2.8.9 (not bleeding edge but I'm only exploring) and KDevelop 4.x
Thanks for your help.

CMake with Xcode 5 : how to add external libraries as 'Target Dependencies' instead of linker flags?

We are building our software under OS X (10.8 at the moment). The project build is managed by CMake (2.8.12).
External dependencies (i.e. not target added by project's CMakeLists) are handled using what we undestood as the canonical way :
Calling find_package(${external_lib}) from a root CMakeLists.
If a given target needs to link against the previously found package, the target's CMakeLists calls target_link_libraries(${TARGET_NAME} ${${external_lib}_LIBRARIES})
The procedure works nicely from a building perspective (the target is actually linked against the external library). Yet the external library is actually given as an additional flag to the compiler, in Build Settings::Other Linker Flags, when it seems that Xcode native way for doing this would be to add the dirname to Build Settings::Library Search Path, and the basename to Build phases::Target Dependencies.
Is there a way to achieve this behavior (without breaking the behavior for other platforms) ?
The behavior of CMake was changed years ago to use full paths.
http://www.cmake.org/cmake/help/v3.0/policy/CMP0003.html
Why do you want to split it?

How to change architecture mac os x

Hi all I need to change architecture type in the file.
when I do lipo -info command I get only arm7 but I need to have i386 next to it.
Is there any command that can add me i386 info inside the file?
Yes, it's called cc, but it depends on some minor configuration files (*.m or *.c files).
Edit: Sorry for not making the joke obvious. What I wanted to say is:
There's not way to change the architecture of an executable file. Executables are produced by compiling source code to machine code and this process is not reversible. You'll need the original source code to recompile the project to the missing architecture. Then you can use lipo to combine the executables to a fat binary.

Resources