Rewrite output suffixes in CMAKE_C_LINK_EXECUTABLE toolchain variable - cmake

Let's say I have a custom C compiler for a special target (not GCC-like). Therefore, I use a custom toolchain file with cmake. Among other things, the linker is supposed to generate multiple outputs at once (elf, hex and map files). The primary output is the ELF file, others are nice-to-have.
So I define something like this in the toolchain file:
set(CMAKE_C_LINK_EXECUTABLE ... --elf-output <TARGET>.elf --hex-output <TARGET>.hex --map-output <TARGET>.map)
The problem with this approach is that the resulting build config does not have the proper dependency. The generated target has its simple name without any suffix. Therefore, multiple calls of the build keep rerunning the linker. I tried working around this the same way it's done on Windows and specified set(CMAKE_EXECUTABLE_SUFFIX_C ".elf") and removed .elf from the mentioned variable. This makes the default target name look right and the linker rerunning issue is gone. But the disadvantage is that now the additional outputs get this .elf suffix into their filenames, i.e. I get foo.elf.hex and foo.elf.map .
Is there a proper way to access the <TARGET> contents without the suffix, which would work in the toolchains definitions?
I could obviously drop this part from the toolchain definition completely and do that path manipulation the cmake project code and attach the proper options via target_link_options, but it just doesn't feel right.

Use TARGET_BASE. From https://github.com/Kitware/CMake/blob/master/Modules/CMakeCInformation.cmake :
# variables supplied by the generator at use time
# <TARGET>
# <TARGET_BASE> the target without the suffix
...
Examples:
$ cd /usr/share/cmake/Modules
$ ag TARGET_BASE
Compiler/ARMCC.cmake
33: set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS> -o <TARGET> --list <TARGET_BASE>.map")
Compiler/ARMClang.cmake
138: set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES> <OBJECTS> -o <TARGET> ${__CMAKE_ARMClang_USING_armlink_WRAPPER} --list=<TARGET_BASE>.map")

Related

CMake how to get binary target complete directory and name on Windows

Is there a way in CMake to find a binary target complete name (mybin.exe) by inspecting target properties? Like
get_target_property(EXENAME targetname OUTPUT_NAME) (or RUNTIME_OUTPUT_NAME)
Or I have to use a custom command like in How to get library full-native name on cmake?
With get_target_property seems I'm only able to get the "logical" target name out of it (mybin), with no other information. Am I missing something?
Thank you
There's a reason this is not possible without generator expressions: There are multi configuration generators such as the Visual Studio generators that create a build system for multiple build configurations (Release, Debug, ...) in a single CMake configuration run (cmake -S ... -B ...). It's even the default to create binaries in a directory with a name matching the configuration built.
Depending on what you want to do with the information, there are some alternatives:
You may be able to use generator expressions, e.g. if you need the information as part of add_custom_command, add_custom_target, add_test or similar. Several target properties also allow for use of generator expressions.
You may be able to establish the desired directory structure during an install step, see the install() command.
You may be able to get the build system to generate the files in a specific location e.g. by setting the CMAKE_RUNTIME_OUTPUT_DIRECTORY variable in the toplevel CMakeLists.txt. Note that this will still result in configuration dependent subdirectories being created for multi configuration generators, unless the variable value contains a generator expression. (You could, simply be adding $<0:>, but this could easily result in binaries of different configurations overwriting one another.)
If you cannot specify this in the toplevel CMakeLists.txt, via command line or cmake presets, you could still use a path relative to CMAKE_BINARY_DIR; this should make the binaries easy to locate.
In the end that is a matter of doing:
add_custom_command(TARGET ${your_target}
POST_BUILD
WORKING_DIRECTORY ${your_dir}
COMMAND echo "$<TARGET_FILE:${your_target}>" > "exename.txt"
DEPENDS ${your_target} ${another_target}
VERBATIM
)
so that exename.txt contains the full path to the executable target
Didn't find a way to do st like:
set(EXENAME "$<TARGET_FILE:${your_target}>")
anyway...

CMake Toolchain File for GHS

I am trying to create a cmake toolchain file for the GreenHills compiler.
When I am using cmake -T C:\ghs\multi506 everything works fine.
But after creating a toolchain file with the line
set(GHS_TOOLSET_ROOT C:/ghs/multi506) I get the error message:
CMake Error: No GHS toolsets found in GHS_TOOLSET_ROOT "C:/ghs/multi506/"
What is the problem?
The use of -T and GHS_TOOLSET_ROOT is finicky. This is because of trying to maintain backward compatibility with the original generator implementation of trying to find the "latest" compiler.
'-T' takes either a absolute path or a relative path.
-T C:\ghs\multi506 means that the compilers are in this directory. It will contain gbuild.exe, etcetera.
-T multi506 will append multi506 to GHS_TOOLSET_ROOT. Therefore CMake will look for gbuild.exe in C:\ghs\multi506.
If you don't use -T then auto search mode is enabled. CMake will search for directories named comp_[^;]+, which is the naming scheme Green Hills uses for its compilers, in GHS_TOOLSET_ROOT. So in this case it will be looking for something like C:\ghs\multi506\comp_20210504.
I prefer using -T with an absolute path to the compiler directory.

CMake to produce -L<path> -l<lib> link flags for static libraries

I'm using CMake 2.8 in order to build an application based on MQX OS (using CodeWarrior).
The CMake project basically builds a set of static libraries (let's say LIB1 and LIB2).
I then reference these libraries in the final executable cmake rule:
target_add_executable(X ${some_sources})
target_link_libraries(X LIB1 LIB2)
My problem is that some symbols are defined in more that one library.
Thus, a link command like:
mwldarm <args> -o <output> <objects> /path/to1/libLIB1.a /path/to2/libLIB2.a
would lead to multiple definition of symbols error.
Instead, I would like CMake to generate a link command like:
mwldarm <args> -o <output> <objects> -L/path/to1 -L/path/to2 -lLIB -lLIB2
Question: How to get the following variables from CMAKE?
Libraries directories flags (ex: -L/path/to1 -L/path/to2)
Libraries link flags (ex: -lLIB -lLIB2)
I've read stuff concerning RPATH but it seems to concern shared libraries only. Am I right?
Thanks for advance.
I do appreciate.
It seems that policy CMP0003 may be what you need.
To use it add the following line near the beginning of your CMakeLists.txt:
CMAKE_POLICY( SET CMP0003 OLD )
Another possibility is to directly set the dependencies and search path, however it's not the cleanest way. Assuming you libraries are called liba.a and libb.a, then:
LINK_DIRECTORIES( ${paths_to_search_for} )
TARGET_ADD_EXECUTABLE(X ${some_sources} )
ADD_DEPENDENCIES(X LIB1 LIB2)
TARGET_LINK_LIBRARIES(X a b )
Note that in this case a and b are not cmake targets, therefore a little machinery is needed to correctly set the dependencies.
Part of the design of CMake is that it links with full paths. Why is that a problem?
Toggling the behavior with the policy is not the correct approach.
http://www.cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd4fa896b
I think CMP0003 is used to switch on/off the function of adding searching path automatically as described in the official document
Libraries linked via full path no longer produce linker search paths.
rather than about replacing the path name with -l.
When linking a library, if the library is a target CMake known, CMake always replaces related -L and -l options with the library's path name. This may not be a problem for linking static libraries. But for a executable to link a shared library, it's may be a problem. Then I found a hacking method, code like below, to solve the problem linking a shread library using -L and `-l' rather than absolute path.
# Find out the link.txt
set(LINK_TXT "${CMAKE_BINARY_DIR}/${ToLinkLib}/CMakeFiles/${ToLinkLIb}.dir/link.txt")
# Add the searching path into link command
add_custom_command(TARGET ${YourTarget} PRE_BUILD
COMMAND sed ARGS -ie "\"s;[[:blank:]]-l; -L${LIBRARY_OUTPUT_PATH} -l;\"" ${LINK_TXT}
DEPENDS ${LINK_TXT}
COMMENT "Hacking CMake: edit __link.txt__ to use -l instead of path to link internal library ...")
# NOTE: Dont't missing the `-l'.
target_link_libraries(${YourTarget} -l${ToLinkLib})
Of course, this is just a hacking so may not be working well with all versions of CMake.
UPDATED: why linking a shared library may be a problem?
When I run a executable cross compiled for android, which linking a shared library built by the same CMake scripts, I've encounter a problem of linking failed. After I used the above hacking method to get a new version, I can run my executable with a command like below
$ LD_LIBRARY_PATH=. ./the_exe opts

Defining dependency between custom commands in different directories

I have a project in which the output of one custom command is used as the input to another, but in a different directory. So for example:
Directory lib/CMakeLists.txt contains:
add_custom_command(
OUTPUT libfoo.xx
COMMAND <command to build libfoo.xx>
)
add_custom_target(libfoo DEPENDS libfoo.xx)
Directory test/CMakeLists.txt contains:
add_custom_command(OUTPUT test.yy
COMMAND <command to build test.yy>
DEPENDS "${PROJECT_BINARY_DIR}/lib/libfoo.xx"
)
So I need to make sure that libfoo is build before test.yy. The docs say that the DEPENDS clause of add_custom_command() can only have file-level dependencies. Let's try that and see what happens:
No rule to make target 'lib/libfoo.xx', needed by 'test/test.yy'. Stop.
If on the other hand, I attempt to create a target-level dependency by saying DEPENDS libfoo, then the error changes to:
No rule to make target 'libfoo', needed by 'test/test.yy'. Stop.
So it seems neither file-level or target-level dependencies will work here. Is there any way to have the output from one custom command be the input to another custom command, in a different directory?
You could try in test/CMakLists.txt to add
add_custom_target(test DEPENDS test.yy)
and then to add
add_dependencies(test libfoo)
in your top-level CMakeLists.txt.
Disclaimer: I didn't test it and I'm a CMake beginner. Tell us if it works!

Only run C preprocessor in cmake?

I'm trying to use cmake to simplify distributing my OpenCL program. I have a kernel file which includes several headers and other source files, and I want to have a single self contained executable.
My plan is to have cmake run the C preprocessor on the kernel source, turning the cl file and its includes into a single unit which is easier to work with.
I can use add_custom_command to do it by calling gcc/clang with -E, but then I don't get the flags to include the right directories to find the various header files in the command, and I don't see an easy way to find all current include directories to use in the custom call to the compiler.
Is there a way to run only the C preprocessor on a file with the current cmake environment?
CMake automatically generates make targets for preprocessing files. For each foo.c in your project there's a foo.i make target that will run only the preprocessor (with all the relevant -D and -I flags etc.). Run make help to see all other potentially useful targets that CMake generates in your makefiles.
BTW, I can't see how this "single unit" will be easier to work with for you.
This worked ok so far:
function(add_c_preprocessor_command)
# Add custom command to run C preprocessor.
#
# Arguments
# OUTPUT output file
# SOURCE input file
# TARGET CMake target to inherit compile definitions, include directories, and compile options
# EXTRA_C_FLAGS extra compiler flags added after all flags inherited from the TARGET
set(one_value_args TARGET SOURCE OUTPUT)
set(multi_value_args EXTRA_C_FLAGS)
cmake_parse_arguments(CPP "" "${one_value_args}" "${multi_value_args}" ${ARGN})
string(TOUPPER ${CMAKE_BUILD_TYPE} build_type)
string(REPLACE " " ";" c_flags "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${build_type}}")
add_custom_command(
OUTPUT ${CPP_OUTPUT}
COMMAND ${CMAKE_C_COMPILER}
"-D$<JOIN:$<TARGET_PROPERTY:${CPP_TARGET},COMPILE_DEFINITIONS>,;-D>"
"-I$<JOIN:$<TARGET_PROPERTY:${CPP_TARGET},INCLUDE_DIRECTORIES>,;-I>"
${c_flags}
$<TARGET_PROPERTY:${CPP_TARGET},COMPILE_OPTIONS>
${CPP_EXTRA_C_FLAGS}
-E ${CPP_SOURCE} -o ${CPP_OUTPUT}
COMMAND_EXPAND_LISTS VERBATIM
IMPLICIT_DEPENDS C ${CPP_SOURCE}
DEPENDS ${CPP_SOURCE})
endfunction()
This will be a crude hack, but you can abuse add_definition for that, as "This command can be used to add any flags, but it was originally intended to add preprocessor definitions."
Alternatively you could just set the COMPILE_FLAGS property of the target to "-E", which will achieve the same effect but be local to that target.
I would suggest a different approach.
Build your kernel into a binary (example for ATI Stream: http://developer.amd.com/support/KnowledgeBase/Lists/KnowledgeBase/DispForm.aspx?ID=115 )
Compile this binary data into your program (as a char[] blob) and load it when your program starts.
With cmake and custom targets this should be quite simple.