[cmake-developers] Recommended use of imported targets...
Alexander Neundorf
neundorf at kde.org
Wed Feb 27 16:37:19 EST 2013
Hi,
in old-style cmake, you do
find_package(Foo)
...
target_link_libraries(hello ... ${FOO_LIBRARIES} )
If Foo was not found, and you forgot to check for it, you get:
CMake Error: The following variables are used in this project, but they are
set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake
files:
FOO_LIBRARIES
linked by target "hello" in directory /home/alex/src/tests/cmakelink
This is a good error message and you get it at cmake time.
If you make a typo:
target_link_libraries(hello ... ${FOOX_LIBRARIES} )
the variable will most likely be empty and you'll get "undefined references to
...whatever" when linking, which is a strong hint that some library is
missing.
Now to new-style cmake usage with imported targets:
find_package(Foo NO_MODULE REQUIRED)
...
target_link_libraries(hello ... foox )
Here the user used the imported target directly, but made a typo.
Now he'll get at link time: "ld: cannot find -lfoox"
This looks like there should be a library libfoox.so somewhere, but is not.
So in this regards cmake failed, if the configure run of cmake ended
successfully, this should be more or less the guarantee that everything that's
needed, including libraries are available.
I see a problem here.
If we recommend to use imported targets directly, those errors will become
relatively common. People forget the "REQUIRED", or make typos, or the
imported targets are renamed. There is no chance to detect that from cmake.
Two ideas:
1) we should continue to recommend to use the variables (which will now be set
to the name of the target). In case of typos, this will lead to an empty
variable (as it did before with Find-modules), and undefined references when
linking. This is at least no regression.
Also, it shields users somewhat from potential renaming of the imported
targets. This should not happen, but who knows. (I just renamed targets in
kdelibs, and they were referenced directly by name in a using project, so I
got the "cannot find -lfoo" errors).
2) tll() can basically only guess whether some string "foo" is a library, so
"-l" has to be added or whether it is a target. Without imported targets this
is relatively safe, since all targets are defined within the project, so in a
quite narrow scope, and it is in the hand of the developer to use the correct
names from within the project. Now when more and more targets will be
imported, many things, influenced by those external packages, can go wrong.
Having to mark strings explicitely as targets (and not as file paths or
library names) would solve this.
safe_target_link_libraries(hello TARGET:foox
FILE:/opt/lib/libbar.a
LIBRARY:png)
(I didn't want to start with this again, but I'm afraid this leads back to the
"use a completely new command for using all the target properties")
So, I'm afraid that in two years from now when there will be a lot of
exporting and importing targets going on, getting failures like above "ld:
cannot find -lKF5::KArchive" will be common, and the resulting errors will be
cryptic to users.
I think this is something we really should try to avoid, since this would kind
of defeat the purpose of the configure run (finding out reliable facts about
the current system).
If we'll rely a lot on imported targets in the future, let's make them as
robust and easy-to-debug as possible.
Comments ?
Alex
More information about the cmake-developers
mailing list