What is the point of ALIAS in cmake? [duplicate] - cmake

This question already has answers here:
Using alias targets in CMake
(1 answer)
cmake usefulness of aliases
(2 answers)
Closed 4 years ago.
In a lot of tutorials and cmake examples I see, it is suggested that you provide aliases with ::s in the name:
add_library(foo a.cxx b.cxx c.xx)
add_library(N::foo ALIAS foo)
What is the point of doing such a thing? Is there a case where using N::foo subsequently solves a problem that using foo directly might have? Why is this considered good practice?

Citing the documentation regarding alias targets:
A primary use-case for ALIAS targets is for example or unit test
executables accompanying a library, which may be part of the same
buildsystem or built separately based on user configuration.
add_library(lib1 lib1.cpp)
install(TARGETS lib1 EXPORT lib1Export ${dest_args})
install(EXPORT lib1Export NAMESPACE Upstream:: ${other_args})
add_library(Upstream::lib1 ALIAS lib1)
With other words, as alias with different computer systems, it makes the names less technical and more human-readable / user-friendly.

Related

CMake: How to manage multiple dependency to the same submodule?

I am trying to build a correct CMake structure for a simple project with several nested submodules. Similarly to this post, I am facing a situation where the main executable and one of the submodules both depend on another submodule:
executable_A/
CMakeListst.txt
library_B/
CMakeLists.txt
library_C/
CMakeLists.txt
library_C/
CMakeLists.txt
Multiple builts of the same target would then result in a cmake error:
add_library cannot create target "library_C" because another target with the
same name already exists. The existing target is an interface library
created in source directory ".....".
See documentation for policy CMP0002 for more details.
The issue had been closed with the following solution, that consists in cheking if the concerned target had already been built before building it again:
# When include 'C' subproject
if(NOT TARGET library_C)
add_subdirectory(C)
endif()
I agree with one of the commenters of the original posts in thinking that it is not a satisfactory solution in every case: in the (unlikely) case of executable_A and library_B depending on different versions of library_C, a mismatch would occur. Is there a way, using submodules, of avoiding this scenario ? Is it possible, for example, to "rename" the library_C target built from library_B to library_C_B, so that no naming conflicts occur ?

How can I avoid clashes with targets "imported" with FetchContent_MakeAvailable?

Suppose I'm writing an app, and managing its build with CMake; and I also want to use a library, mylib, via the FetchContent mechanism.
Now, my own CMakeLists.txt defines a bunch of targets, and so does mylib's CMakeLists.txt. If I were to install mylib, then find_package(mylib), I would only get its exported targets, and even those would be prefixed with mylib:: (customarily, at least). But with FetchContent, both my app's and mylib's (internal and export-intended) targets are in the "global namespace", and may clash.
So, what can I do to separate those targets - other than meticulously name all of my own app's targets defensively?
I would really like it if it were possible to somehow "shove" all the mylib targets into a namespace of my choice.
Note: Relates to: How to avoid namespace collision when using CMake FetchContent?
In the current CMake (<=3.24) world, there are no features for adjusting the names of the targets in other black-box projects, whether included via find_package, add_subdirectory, or FetchContent. Thus, for now, it is incumbent on you to avoid name-clashes in targets, install components, test names, and anywhere else this could be a problem.
Craig Scott says as much in his (very good) talk at CppCon 2019, see here: https://youtu.be/m0DwB4OvDXk?t=2186
The convention he proposes is to use names that are prefixed with SomeProj_. He doesn't suggest to literally use ${PROJECT_NAME}_, and I wouldn't either, because doing so makes the code harder to read and grep (which is extremely useful for understanding a 3rd-party build).
To be a good add_subdirectory or FetchContent citizen, however, it is not enough to simply namespace your targets as SomeProj_Target; you must also provide an ALIAS target SomeProj::Target. There are a few reasons for this:
Your imported targets from find_package will almost certainly be named SomeProj::Target. It should be possible for consumers of your library to switch between FetchContent and find_package easily, without changing other parts of their code. The ALIAS target lets you expose the same interface in both cases. This will become especially pressing when CMake 3.24 lands with its new find_package-to-FetchContent redirection features.
CMake's target_link_libraries function treats names that contain :: as target names always and will throw configure-time error if the target does not exist. Without the ::, it will be treated as a target preferentially, but will turn into a linker flag if the target doesn't exist. Thus, it is preferable to link to targets with :: in their names.
Yet, only IMPORTED and ALIAS targets may have :: in their names.
Points (2) and (3) are good enough for me to define aliases.
Unfortunately, many (most?) CMake builds are not good FetchContent citizens and will flaunt this convention. Following this convention yourself reduces the chance of integration issues between your project and any other, but obviously does nothing to prevent issues between two third party projects that might define conflicting targets. In these cases, you're just out of luck.
An example of defining a library called Target that will play nice with FetchContent:
add_library(SomeProj_Target ${sources})
add_library(SomeProj::Target ALIAS SomeProj_Target)
set_target_properties(
SomeProj_Target
PROPERTIES
EXPORT_NAME Target
OUTPUT_NAME Target # optional: makes the file libTarget.so on disk
)
install(TARGETS SomeProj_Target EXPORT SomeProj_Targets)
install(EXPORT SomeProj_Targets NAMESPACE SomeProj::)
For a more complete example that plays nice with install components, include paths, and dual shared/static import, see my blog post.
See these upstream issues to track the progress/discussion of these problems.
#22687 Project-level namespaces
#16414 Namespace support for target names in nested projects
As #AlexReinking , and, in fact, Craig Scott, suggest - there's no decent current solution.
You can follow the following CMake issues through which the solution will likely be achieved:
#22687 Project-level namespaces (more current)
#16414 Namespace support for target names in nested projects (longer discussion which influenced the above, recommended reading)

What's the idiomatic way to compile the same file twice, with different languages?

I have a source file which is valid in (at least) two languages. Say, C and C++ or C and CUDA.
I want to compile this file in both languages, each time into a different library. What's the idiomatic way of doing this in recent versions of CMake?
Notes:
If the specific version of CMake matters, please specify which minimum version I would need.
Related: How can I configure cmake to compile a file twice with two different compilers?
This elaborates on #KamilCuk's suggestion in a comment on the OP, written before I noticed the comment.
The LANGUAGE property is set on the source file itself, which is the core of your question. The documentation for this property describes it being visible in the scope of the directory where it is set. That means that one way to have different languages is to set the property in two different directories. For example:
src/
CMakeLists.txt
common/
main.c
app1/
CMakeLists.txt
app2/
CMakeLists.txt
src/CMakeLists.txt:
add_subdirectory(app1)
add_subdirectory(app2)
app1/CMakeLists.txt:
set_property(SOURCE ../common/main.c PROPERTY LANGUAGE CXX)
add_executable(app1 ../common/main.c)
app2/CMakeLists.txt:
set_property(SOURCE ../common/main.c PROPERTY LANGUAGE C)
add_executable(app2 ../common/main.c)
This will build main.c into two different targets, with two different LANGUAGE settings.
The docs also hint at being able to set the property explicitly against other directory scopes including binary directories. I was hoping this would help make the job simpler, but I can't get it to work.
Since, indeed, LANGUAGE is a per-file property, I believe what should happen - and would allow for a proper idiom here - is to have a binary relation of language-to-use for pairs of (target, source file).
I've suggested this to KitWare in an issue report (gitlab.kitware.com).

Setting project wide compiler options [duplicate]

This question already has an answer here:
What is the modern method for setting general compile flags in CMake?
(1 answer)
Closed 1 year ago.
I want to use CMake to create modular embedded C++ software. I separated hal-drivers static library, some common-utils library and top target device depends on those two what is marked using target_link_libraries like this:
target_link_libraries(device
PRIVATE
hal-drivers
common-utils
)
It is easy to propagate compile definitions and option up in "dependency ladder" using commands like this:
target_compile_definitions(hal-drivers
INTERFACE
STM32F415xx
USE_HAL_DRIVER
)
This way any target utilising hal-drivers header files will preprocess those headers correctlym, and I found this CMake scripts feature (propagation of "settings") great, but it is not the point of this question.
The question is how should I propagate common compiler options like for example -fdata-sections or -Wall for every target in my project? I know I can
create dummy (no source and no header files, just compile options) interface target which will be consumed by every other target in project but this looks like a workaround...
specify mentioned compiler options for every target separatly, since I have only about 5 targets, but it will be very problematic to maintain.
In my commercial work project (50 targets) my boss ended up with an ugly compromise: setting common compile options in top CMakeLists.txt as cached variable and then applying this variable in all targets manually, but we dont like it at all.
Bear in mind: I do have solutions that work, I am interested in recomended solutions. Also I am using Professional CMake: A Practical Guide 9th Edition on daily basis (its a great book), but I failed to found answer on my question in this book.
I found an answer.
I guess my whining about lack of elegant solution is due to my attachment to syntactic sugar like target_compile_options, but the thing is CMake evolved in hardship and not every CMake feature is pretty, but it works.
There is an answer: https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS.html
The flags in this variable will be passed to the compiler before those in the per-configuration CMAKE_<LANG>_FLAGS_<CONFIG> variant, and before flags added by the add_compile_options() or target_compile_options() commands.
So I have to append my custom options to this special CMake variable like this:
project(Device C CXX ASM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdata-sections")
This way it will flood all targets with fdata-sections.
Leaving this thread as interesting note.

Naming convention for components and namespaces in cmake

In Short:
Is there any preferred naming convention for cmake library targets - in particular when using namespaces?
Note:
Unless there is really an objective reason for it, I'm not asking about personal preferences, but whether there is either an "official" (e.g. recommended by kitware) or established (which might deviate) convention.
Details:
Lets say I have a library/framework foo which has the individual components bar and baz. So far, my naming convention looks like this:
add_library(foo-bar src1.cpp, scr2.cpp)
add_library(foo-baz src3.cpp, src4.cpp)
Now I want to add alias targets using the namespace (::) convention. E.g.
add_library(Foo::Bar ALIAS foo-bar)
add_library(Foo::Baz ALIAS foo-baz)
(Of course the question also extends to export sets, but I didn't want to complicate the question)
What I couldn't really find out however, is if there is a preferred or even official naming convention for those targets.
Things I've seen:
Namespace part:
some projects seem to capitalize the first letter, some not (the former seems to be more common)
Component part:
in some projects, the component name is the same as the binary name
with or without the "lib" prefix (libfoo-bar vs foo-bar)
with or without the namespace (foo-bar vs bar)
some projects capitalize the first letter
some projects use CamelCase some snake_case, even if the binaries or project names don't follow those conventions.
I guess the main problem is that there is no naming convention for libraries in general so that makes it hard to come up with a naming convention in CMake, but at least the capitilization for the first letter of the namespace and the component seem to be pretty common, so I was wondering if there is some guideline I should follow for future projects.
The cmake-developer documentation gives the following advice on namespaces:
When providing imported targets, these should be namespaced (hence the Foo:: prefix); CMake will recognize that values passed to target_link_libraries() that contain :: in their name are supposed to be imported targets (rather than just library names), and will produce appropriate diagnostic messages if that target does not exist (see policy CMP0028).
And the CMP0028 policy documentation says on the "common pattern" in the use of namespaces:
The use of double-colons is a common pattern used to namespace IMPORTED targets and ALIAS targets. When computing the link dependencies of a target, the name of each dependency could either be a target, or a file on disk. Previously, if a target was not found with a matching name, the name was considered to refer to a file on disk. This can lead to confusing error messages if there is a typo in what should be a target name.
And no, there are no CMake specific convention for the naming of library targets. But since the name is taken by default as the target's output name:
I prefer to take the same name for the targets as for my source code directory
And add no lib prefix, since this is automatically added by CMake depending on the platform you are compiling your project with
From the CMake Tutorial
The most official source you could get is probably an extract from the "Mastering CMake" book written by Ken Martin and Bill Hoffman from Kitware.
The tutorials from the book all use CamelCase and no namespaces for component/target names.
References
What is the naming convention for CMake scripts?
cmake usefulness of aliases