I have a problem with cmake target_link_libraries.
I have 3 libs. The first is static compiled, the second one (shared lib) link to it and the third one is an executable which use the second lib.
My problem is that my first lib is automatically added to the third lib and leads into a "object already defined" problem.
Is it possible to hide away the first lib from the third one?
I use cmake 3.4.x
Compiler: msvc 2010 x64
Thanks in advance
Tonka
Your third "lib" isn't a library, but an application. You need to add this using add_executable, not add_library.
If your shared library links in a static library, and then you want to link an application to both the static library and that shared library, you get two copies of the static library. Never link static libraries you plan to use elsewhere into a shared library, for this reason. Either make the first shared as well (the name implies that's what you want, as it is exactly what you are describing), or a workaround for this design problem could be to not explicitly link the application to the static library.
I've solved it. I can link to a library private, so f.e.
target_link_libraries(MyLib2 PRIVATE MyLib1)
will hide MyLib1 from everybody linking to MyLib2
Related
I am trying to figure out how CMake is supposed to work for shared libraries. I create a shared library like so:
(in /mdp_opt/CMakeLists.txt:)
add_library (mdp_opt SHARED librarycomponent.cpp)
Now, a test executable uses this library:
(/test/CMakeLists.txt:)
add_executable (test test.cpp)
target_link_libraries(test PRIVATE mdp_opt)
If the library is marked STATIC (instead of SHARED as above), I can cmake -> built (under Visual Studio) and successfully run the executable. When it is marked SHARED (as in above), I need to do two things. First thing, is adding:
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
That is fine. However, now it still only works if I copy the file mdp_opt.dll from build/x64-debug/mdp_opt to build/x64-debug/test. But I don’t understand why this is needed?
In the book “professional CMake”, I read:
LINK_LIBRARIES
This target property holds a list of all libraries the target should
link to directly. It is initially empty when the target is created and
it supports generator expressions. An associated interface property
INTERFACE_LINK_LIBRARIES is supported. Each library listed can be one
of the following (emphasis mine):
• A path to a library, usually specified as an absolute path.
• Just the library name without a path, usually also without any
platform-specific file name prefix (e.g. lib) or suffix (e.g. .a, .so,
.dll).
• The name of a CMake library target. CMake will convert this to a
path to the built library when generating the linker command,
including supplying any prefix or suffix to the file name as
appropriate for the platform. Because CMake handles all the various
platform differences and paths on the project’s behalf, using a CMake
target name is generally the preferred method.
I was under the impression that
target_link_libraries(test PRIVATE mdp_opt)
expresses that I intend to link the output associated with the target mdp_opt with the test executable? Also, in my reading of the above book excerpt, my understanding is that the location of the .dll will convert to a path? If the purpose of this conversion is not to somehow tell the executable where to find the shared library, then what is that conversion for?
Basically, can anybody tell me how CMake is supposed to work for shared libraries, and why is works like that? Is a manual post-copy (possibly via CMake instructions) really needed, and the best for this scenario (of intermediate builds while developing)?
On windows you need to export symbols of a shared library or add a linker option that results in symbols being exported; otherwise the .lib file for linking the dll simply isn't generated. This is why you need
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
, use __declspec( dllexport ) or similar.
The other issue is the way windows locates dlls: It basically first searches the directory containing the executable and then continues the search via the PATH environment variable. This can result in issues locating the dll at runtime.
You can avoid this issue by setting the directory to place the runtime artefacts before generating the first one of the targets involved:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
...
add_library(mdp_opt ...)
...
add_executable(test ...)
Alternatively you could simply change the environment variable visible to the vs debugger:
set_target_properties(test PROPERTIES VS_DEBUGGER_ENVIRONMENT "PATH=$<TARGET_FILE_DIR:mdp_opt>;$ENV{PATH}")
If you're working with CTest, there's also a similar property for tests: ENVIRONMENT
If the purpose of [target_link_libraryes] is not to somehow tell the executable where to find the shared library, then what is that conversion for?
You still need to link a dll, or more precisely the corresponding import library; this is what target_link_libraries does, in addition to adding build system dependencies, transferring some properties (e.g. include directories with PUBLIC visibility), ect.
Long story short, I rewrote the Godot build system to cmake (only windows part), mostly because I wanted to learn it, but I have trouble compiling Godot with mingw. When I'm trying to compile it, at first everything goes fine, up until the point of linking final exe, where I get a lot of "undefined reference to" errors. It looks like main libraries (core/scene/editor/..) can't see functions from each other. MSVC build is working fine, and scons version is also compiling under mingw, so I clearly just missed something in my cmake version.. I tried to remove some compile/linking options throughout my cmake scripts as a test, but nothing changed. I don't really know how even debug this problem, so if someone could kick me in the right direction I would be really glad for it.
Ok, I finally got time to came back to this.
The problem
So basically the problem was in circular dependency on godot libs. I didn't thought this was the problem because I'm spoiled by MSVC (which doesn't depend on link order). Also, I tried to replicate circular dependency in mingw on a test project with much smaller scale. The project was a 30 libs with two functions in each, first function printing string, and another calling all first functions from all 30 libs, so there is 30 libs of circular dependency. Strangely enough, the project linked no problems, and printed 30^2 strings..
The solution
The solution is to use -Wl,--start-group/-Wl,--end-group linking flags around all libraries. There is two ways you can do it.
First way, is to add all your libraries to the some list of sorts. This could be global property, or property on some target (not just a simple variable), so it could be accessed from other subdirectories. After you formed your list of libraries you simply link it to the executable as follows
# getting all your libs from the global property..
get_property(__LIBS_LIST GLOBAL PROPERTY EXE_LIBS_LIST)
# linking all libraries to the exe..
target_link_libraries(my-exe PRIVATE -Wl,--start-group ${__LIBS_LIST} -Wl,--end-group)
This is the easiest solution, but be cautious about dependencies on libraries which you link to your exe, because it seems that when CMake creates link line for your exe, it first lists all libraries which are linked directly to your exe, and only after it places libraries which came from dependencies of libraries linked directly. Basically if your target dependency tree looks something like this:
exe // your main exe file
- lib_A // lib A linked directly to the main exe
- lib_AA // lib AA linked to the lib_A
- lib_AAA // lib AAA linked to the lib_AA
- lib_B // lib B linked directly to the main exe
- lib_BB // lib BB linked to the lib_B
- lib_BBB // lib BBB linked to the lib_BB
your link order for the exe will look something like this:
// first libs linked directly to the exe
lib_A
lib_B
// only after recursively initial libs dependencies
lib_AA
lib_AAA
lib_BB
lib_BBB
That's meen, that if you will link your libs like target_link_libraries(my-exe PRIVATE -Wl,--start-group ${__LIBS_LIST} -Wl,--end-group), --start-group and --end-group will guard only the libraries linked directly to your exe. I didn't found this described in documentation, but I found SO question which talks pretty much about same behaviour (CMake library linking order). Also, as I tested this on mingw, it didn't mattered how exactly libs lib_AA/lib_AAA/lib_BB/lib_BBB were linked, via PRIVATE or via INTERFACE, the results were the same.
Second way, is to exploit recursivity of link expanding for dependencies of libraries linked directly to the exe. From my example you can see, that dependencies of lib_A (lib_AA/lib_AAA) weren't mixed with dependencies of lib_B (lib_BB/lib_BBB). So basiacaly what we can do, is to create INTERFACE library and connect to it -Wl,--start-group immediately after that. Then add any number of libraries to it's interface and link global-libs to your exe (order does not matter). And in very end, close the group in your global-libs library
add_library(global-libs INTERFACE)
target_link_libraries(global-libs INTERFACE -Wl,--start-group)
# ...
# linking another libs, and linking global-libs to exe
# ...
target_link_libraries(global-libs INTERFACE -Wl,--end-group)
This will ensure, that all libraries connected to global-libs will be surrounded by -Wl,--start-group/-Wl,--end-group.
Now, theoretically, CMake should handle circular dependency by itself, by placing libraries in link line multiple times (how many times controlled by LINK_INTERFACE_MULTIPLICITY). But this method didn't worked for me (mb I just missed something..). Plus, you need declare dependencies between cmake targets, and with -Wl,--start-group/-Wl,--end-group you can just set one specific interface library as a holder for all libs with circular dependencies..
I'm using a compiled library that I made, libexp.a. (Was compiled with PIC so its good for this use case).
I want to use it statically in my shared library and I can do that via Mixing static libraries and shared libraries.
So now I'm trying to get that working with CMake, my libexp.a is in the root directory and I do:
find_library(EXP NAMES exp PATHS ${PROJECT_SOURCE_DIR} NO_DEFAULT_PATH)
Then using it in target_link_libraries via ${EXP}, but during link time I still get a linking error of couldn't find -lexp. What is the right way to get this done? Using over 3.6
The title mostly covers it, what is the difference between a module and a shared library? I just found this distinction in CMake's add_library command, where they say:
SHARED libraries are linked dynamically and loaded at runtime. MODULE libraries are plugins that are not linked into other targets but may be loaded dynamically at runtime using dlopen-like functionality.
But I can load a shared object using dlopen(), can't I?
The difference is that you can link to a SHARED library with the linker, but you cannot link to a MODULE with the linker. On some platforms.
So... to be fully cross-platform and work everywhere CMake works, you should never do this:
# This is a big NO-NO:
add_library(mylib MODULE ${srcs})
target_link_libraries(myexe mylib)
To be fair, on Windows, they're both just dlls, and so this code might actually work. But when you take it to a platform where it's impossible to link to the MODULE, you'll encounter an error.
Bottom line: if you need to link to the library, use SHARED. If you are guaranteed that the library will only be loaded dynamically, then it's safe to use a MODULE. (And perhaps even preferable to help detect if somebody does try to link to it...)
I think the distinction being made is that shared libraries are specified by the developer at compile-time and must be present for the application to run, even though their methods are loaded at runtime. A module, i.e. plugin, adds additional support at runtime but isn't required. Yes, you can dlopen() a shared library but in that case it would not have been specified as a required part of the program and functions instead as a module.
Another difference is in how ..._OUTPUT_DIRECTORY and ..._OUTPUT_NAME are handled:
Module libraries are always treated as library targets. For non-DLL platforms shared libraries are treated as library targets. For DLL platforms the DLL part of a shared library is treated as a runtime target and the corresponding import library is treated as an archive target. All Windows-based systems including Cygwin are DLL platforms.
For example, this means that if you compile a SHARED library on Windows, LIBRARY_OUTPUT_DIRECTORY will be ignored, because it's looking at ARCHIVE_OUTPUT_DIRECTORY and RUNTIME_OUTPUT_DIRECTORY instead.
I would like to create shared library with cmake, but also I need to link it to third party static libraries.
For example if it should include my own file1.o, file2.o, then statically linked libfoo.la and then be written down to disk as .so file which dynamically linked to libbar.so
Is it even possible?
It is possible to link static library to shared library. On most Unixes, you will need
to add -fPIC flag or its equivalent for producing position-independent code when you build static library. On Windows, there is no PIC, i.e linking static to shared just works out of the box.