cmake "exporting" shared library on windows - cmake

I'm writing a small library.
I'd like to build it as shared library and generate "MyLibraryConfig.cmake" file which then can be used by my other projects to find my library.
The only problem I have is to figure out the name/path to file which is used for linking under Windows - there are two files being generated: mylibrary.dll and mylibrary.dll.a.
So I'd like to generate MyLibraryConfig.cmake file with something like:
"set(MYLIBRARY_LIBRARIES /blah/blah/mylibrary.dll.a)"
so then MYLIBRARY_LIBRARIES can be used with target_link_libraries for my other projects.
How can I get name for this linkable file? I'd be nice if the solution was platform independed (returning .so wile on Linux and .dll.a on Windows)
thanks in advance

If you're planning on making your library available to your other projects without installing it then you want the CMake command export. For example:
export(TARGETS MyLib FILE ${CMAKE_SOURCE_DIR}/MyLibraryConfig.cmake)
This creates the file MyLibraryConfig.cmake in the same directory as your top-level CMakeLists.txt, and can just be included in other CMake projects.
If you're planning on installing your library, then you want to make use of install(EXPORT ...) instead:
install(TARGETS MyLib EXPORT MyLibraryConfig
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(EXPORT MyLibraryConfig DESTINATION cmake)
This will install the file MyLibraryConfig.cmake to <install path>/cmake, and can then be included by other projects.

Related

CMake: How to build multiple projects exported for find_package() via add_subdirectory()

I have a Library Project that is exported so consumers can use it like so:
find_package(myLibrary)
target_link_libraries(theirLibrary PUBLIC myNamespace::myLibrary)
MyLibrary is the main product but it lives alongside two other projects in our repository, and the layout looks like this:
MyRepository/
MyLibrary/
CMakeLists.txt
include/ //public headers
MyLibrary/ //sources and private headers
MyDependentLibrary/ //another library project
CMakeLists.txt
etc..
MyExample //executable project
CMakeLists.txt
etc..
The dependencies for each project are like so:
MyLibrary: None
MyDependentLibrary: MyLibrary
MyExample: MyLibrary, MyDependentLibrary
MyLibrary and MyDependentLibrary are both set up with install and build directory exports to be compatible with the find_package() command. So to build everthing you:
configure/build MyLibrary
configure MyDependantLibrary setting MyLibrary_DIR when prompted, then build it
configure MyExample setting MyLibrary_DIR and MyDependentLibrary_DIR when prompted, then build it
This workflow is great, most of the time we only want to package MyLibrary without the other projects when we send to customers, but occasionally we want to give them the source for all 3 projects so they have more examples to look at.
For that reason I would love to add a top level CMakeLists.txt file that would I imagine look something like this:
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(MyCombinedProject VERSION 1.0.0 LANGUAGES CXX)
add_subdirectory(MyLibrary)
add_subdirectory(MyDependentLibrary)
add_subdirectory(MyExample)
However this doesn't work. When configuring the "combined" project, MyDependentLibrary is unable to find MyLibrary_DIR, which makes sense, as MyLibrary hasn't been built yet.
Is there a way to add an export to each of the libraries so they can be found when added in this manner in addition to the find_package()? I really don't want to move any CMake code required to build MyLibrary into the top level CMakeLists.txt, as 90% of the time it will be delivered on its own.
You may ship the sources of your library (MyLibrary) with a pseudo config file, which just provides myNamespace::myLibrary target as alias for myLibrary.
MyLibrary/CMakeLists.txt:
# Assuming you create a library
add_library(mylibrary ...)
# Install and export it
install(TARGETS mylibrary EXPORT mylibraryTargets ...)
# and install the file which describes this installation
install(EXPORT mylibraryTargets NAMESPACE myNamespace ...)
# Then you install config file for your library:
install(FILES myLibrary.cmake ...)
# Then just set `MyLibrary_DIR` variable to point into in-source version of config file.
set(MyLibrary_DIR CACHE INTERNAL "A directory with the in-source config file"
${CMAKE_CURRENT_SOURCE_DIR}/cmake
)
And write that in-source config file as follows:
MyLibrary/cmake/MyLibraryConfig.cmake:
add_library(myNamespace::mylibrary ALIAS mylibrary)
That way, find_package(MyLibrary) will work if it is issued after configuring sources of your library (add_subdirectory(MyLibrary)).

Set output directory for CMake OBJECT libraries

In my CMake file I've specified an object library:
add_library(core OBJECT ${sourcefiles})
I refer to this set of object file in a shared library further on:
add_library(sharedlib SHARED $<TARGET_OBJECTS:core>)
This works fine, however I would like to reuse the build artefacts between different project.
By setting the LIBRARY_OUTPUT_PROPERTY on the sharedlib I can direct the generated .so file to a common directory:
set_target_properties(sharedlib PROPERTIES LIBRARY_OUTPUT_NAME /commondir)
However, I cannot seem to do the same thing for the core (OBJECT) library - the .o files always end up in the (project-specific) generated cmake-build directories.
This means every project will have to rebuild the (large) shared library anyway...
Am I doing something wrong, or is this not (yet?) possible with CMake?
You can't change the output directory of object/intermediate files in CMake. That's by design (to allow several identical output names in one project):
"There is no way to change that name.
CMake creates an exact copy of the source tree in
the binary tree."
But with version 3.9 CMake learned to export object libraries:
cmake_minimum_required(VERSION 3.9)
project(CorePorject)
file(WRITE "core.cpp" "")
file(WRITE "helper.cpp" "")
set(sourcefiles "core.cpp" "helper.cpp")
add_library(core OBJECT ${sourcefiles})
export(
TARGETS core
FILE core.cmake
NAMESPACE Core_
)
References
Set C++ object file output location with CMake
Set the directory for Intermediate files (like .obj) in CMake
Making cmake library accessible by other cmake packages automatically

Creating a findable shared library with cmake

I am rewriting libraries from hand-written Makefiles to using cmake. I am getting stuck at the point where I need to library library A from library B.
I can find the libraries using find_package, but when they are being linked cmake complains about not having a rule for building the .so file because it is looking for it in the build directory instead of the installed directory.
This is explained if I look at the /usr/lib/cmake/library/libraryConfigVersion.cmake file, which contains this hardcoded path. This file was created with the following steps:
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/libraryConfigVersion.cmake"
VERSION ${LIBRARY_VERSION}
COMPATIBILITY AnyNewerVersion
)
export(EXPORT libraryTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/library/libraryConfigVersion.cmake"
NAMESPACE library::
)
(i have replaced my library name with 'library'). How can I get cmake to write the correct path so that I can easily link against my library from other cmake projects?
Command export actually exports build tree. This is explicitely written in the documentation.
For export install tree, use install(TARGETS ... EXPORT) plus install(EXPORT). Both flows are described in documentation for install command.
See also CMake tutorial Exporting and Importing Targets.

cmake add_library, followed by install library destination

I am trying to run cmake to generate makefiles. In the minimum working example, I have three files and 1 build directory.
File 1 is CMakeLists.txt, containing exactly:
add_library (MathFunctions SHARED mysqrt.cxx)
install (TARGETS MathFunctions LIBRARY DESTINATION lib)
File 2 is MathFunctions.h containing the function prototype, function relates to mysqrt.cxx.
File 3 is mysqrt.cxx containing include statement and a function definition.
When I create a build sub-directory and run "cmake ..", I am getting
CMake Error at CMakeLists.txt:2 (install):
install Library TARGETS given no DESTINATION!
Isn't my add_library, then install statement grammar correct? If I remove both SHARED and LIBRARY, cmake builds without errors.
Thanks for your help.
The problem is likely down to you running this on what CMake calls a "DLL platform" and how CMake classifies a shared library on such a platform.
From the docs for install:
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.
So, try changing your command to something like:
install (TARGETS MathFunctions
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)

How to develop shared library in KDevelop?

I want to develop shared library in KDevelop. But i don't see any template for library.
I guess i have to create project from c++ template and edit CMake files in both projects. Unfortunately i have got no experience with library development with CMake, also i want good integration with KDevelop - automatic build of library when i build/run project which uses that library.
To create a library use the add_library command:
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
source1 source2 ... sourceN)
For example:
add_library(mylib SHARED
a.h
a.cpp
b.h
b.cpp)
Would create a shared library from the four files listed.
If your program (created with add_executable) uses the library, when you specify the link with target_link_libraries, CMake will add the dependency, so that if you changed a.cpp the library mylib would be rebuilt and your application would be re-linked.
For example
add_executable(myprog
main.cpp)
target_link_libraries(myprog
mylib)
Edit:
When your library and project are in different folders, you can use add_subdirectory.
Create a CMakeList.txt in each directory, in the library folder use add_library in the application, use add_program and target_link_libraries.
In the parent folder use add_subdirectory, add the library folder first, then the program folder. This will make the library available to the application. Then run cmake against the parent CMakeList.