CMake LibXML Runtime library not found. Windows - c++

I try to create an automated build of Scram (CI yaml file, CMakeLists.txt) for Windows. The project uses CMake to create the build files. Building of the project worked already, but the runtime libraries of libxml and boost get not bundled into the package.
As compiler mingw64 is used.
Libxml2 will be installed by the CI in a previous step and the install prefix is passed to the scram cmake.
In the CMakeLists.txt libxml is included as:
find_package(LibXml2 REQUIRED)
1
I tried then to install the libxmllibraries as:
install(FILES ${LIBXML2_LIBRARIES} DESTINATION bin)
The problem is that LIBXML2_LIBRARIES points to the .dll.a files in the libxml2_install_prefix/lib and not to the .dll files in the libxml2_install_prefix/bin folder. So only the .dll.a files are bundled into the exe and therefore the application does not work.
2
get_target_property(LIB_XML2_RUNTIME_OUTPUT_DIRECTORY LibXml2::LibXml2 RUNTIME_OUTPUT_DIRECTORY)
get_target_property(LIB_XML2_RUNTIME_OUTPUT_NAME LibXml2::LibXml2 RUNTIME_OUTPUT_NAME)
message(STATUS "XX LIB_XML2_RUNTIME_OUTPUT_DIRECTORY: ${LIB_XML2_RUNTIME_OUTPUT_DIRECTORY}")
message(STATUS "XX LIB_XML2_RUNTIME_OUTPUT_NAME: ${LIB_XML2_RUNTIME_OUTPUT_NAME}")
install (FILES
${LIBXML2_LIBRARIES}
"${LIB_XML2_RUNTIME_OUTPUT_DIRECTORY}/${LIB_XML2_RUNTIME_OUTPUT_NAME}"
DESTINATION bin
COMPONENT libraries)
In this case LIB_XML2_RUNTIME_OUTPUT_NAME and LIB_XML2_RUNTIME_OUTPUT_DIRECTORY are "-NOT_FOUND"
This seems to be a problem because cmake does not know the runtime directory for imported targets (
3
I tried than also install(IMPORTED_RUNTIME_ARTIFACTS LibXml2::LibXml2) which failed with: install IMPORTED_RUNTIME_ARTIFACTS given target "LibXml2::LibXml2" which is not an executable, library, or module.
Also described here: CMake Gitlab repository
4
install(TARGETS LibXml2::LibXml2 RUNTIME_DEPENDENCIES)
failed with the following message: install TARGETS given target "LibXml2::LibXml2" which does not exist.
From CMake Docu:
Note: Imported Targets are supported only if they know the location of their .dll files. An imported SHARED or MODULE library must have IMPORTED_LOCATION set to its .dll file. See the add_library imported libraries section for details. Many Find Modules produce imported targets with the UNKNOWN type and therefore will be ignored.
Probably LibXml2 is imported as unknown and therefore there is no DLL path specified. How to come around this issue and installing the dlls?
5
I tried
install(FILES $<TARGET_RUNTIME_DLLS:LibXml2::LibXml2> DESTINATION bin COMPONENT libraries)
but here I get the error message:
Objects of target "LibXml2::LibXml2" referenced but is not one of the allowed target types (EXECUTABLE, SHARED, MODULE).. Probably because the target is imported and not created by this cmake
6
get_target_property(libxml2_imported_location LibXml2::LibXml2 IMPORTED_LOCATION) points also to the .dll.a file
7 Working Hack (Ugly)
Find out where the .dll is located. For libXml2 it is in the bin folder, for boost it is in the same folder as the .dll.a
Use the imported location and replace the path to match the path to the .dll
get_target_property(libxml2_imported_location LibXml2::LibXml2 IMPORTED_LOCATION)
string(REPLACE "/lib/" "/bin/" libxml2_imported_location ${libxml2_imported_location})
string(REPLACE ".dll.a" ".dll" libxml2_imported_location ${libxml2_imported_location})
message(STATUS "XX libxml2_imported_location3 ${libxml2_imported_location}")
install(FILES ${libxml2_imported_location} DESTINATION bin COMPONENT libraries)

Related

Cmake how to manage two package include same sub-project

I wrote an shared library project. The CMakeLists.txt in this project:
install(TARGETS ${library_name}
LIBRARY DESTINATION "lib"
)
install(FILES
${CMAKE_CURRENT_SOURCE_DIR}/lib/libxxx.so
DESTINATION "lib"
)
install(DIRECTORY
data
DESTINATION "/opt/${project_name}"
)
Then, I have two project include that
add_subdirectory(module/xxx)
I use Cpack generate pkg1.deb pkg2.deb;
on installation time error occurred, trying to overwrite "libxxx.so", which is also in package "pkg1.deb", install package failed;
Now, I use dpkg with --force-overwrite temporarily solve this;
Is there a solution to manange this with cmake?

How can I use CMake and FindLibXml2 to link against a static version of LibXml2 that requires no DLL

I am modernizing our CMake build system and switching to static compilation of all dependencies so I can deploy the application as single binary. One of the dependencies is LibXml2 which is statically compiled (Environment MSVC 2019 x64 Native):
cscript configure.js iconv=no compiler=msvc cruntime=/MT debug=yes static=yes prefix=libxml
nmake Makefile.msvc libxml install
This generates the DLL win32\libxml\bin\libxml2.dll and the LIB files win32\libxml\lib\libxml2.liband win32\libxml\lib\libxml2_a.lib.
My CMake file looks like this:
find_package(LibXml2 REQUIRED)
add_executable(testapp WIN32)
target_sources(testapp
PRIVATE
Main.cpp
)
target_include_directories(testapp PUBLIC ${LIBXML_LIBRARIES})
target_link_libraries(testapp PRIVATE LibXml2::LibXml2)
Problem: It looks like the find module FindLibXml2 picks up the relocatable shared DLL, but not the static LIB archive. Thus the application is linked against the dynamic library.
Question: How can I use the find module script, but link against the static version of LibXml2? Is this even possible or do I have to write an own find script?
User #alex-reinking gave the important tip: Set the cached variable before calling the find module - and not afterwards.
Because I don't want to hardcode the path (and can't because I have a debug and release build of LibXml2), I use find_library to find the static library (Note: I added the libxml directory via CMAKE_PREFIX_PATH):
find_library(STATIC_LIBXML2_LIBRARY NAMES libxml2_a)
message(STATUS "Found library: ${STATIC_LIBXML2_LIBRARY}")
set(LIBXML2_LIBRARY ${STATIC_LIBXML2_LIBRARY})
find_package(LibXml2 REQUIRED)

Including external libraries in cpack output

Im currently working on a cmake project which is making use of external libraries which are being imported through the find_package function. My question revolves around cpack and how I am supposed to go about adding the found packages into the cpack output. For example if I use this
find_package(OpenGL REQUIRED)
add_executable(Example_App MACOSX_BUNDLE src/main.cpp)
target_include_directories(Example_App SYSTEM PUBLIC ${OPENGL_INCLUDE_DIR})
target_link_libraries(Example_App PUBLIC ${OPENGL_LIBRARIES})
install(TARGETS Example_App
BUNDLE DESTINATION "."
RUNTIME DESTINATION bin)
If I then run cmake .. followed by make and make package my output from cpack (I can include an example of my cpack code if needed too) would then be.
ExampleApp-linux.tar.bz2
- bin
-- Example_App
- Share
-- Resource files
Rather than something like:
- bin
-- Example_App
- Lib
-- OpenGL.a
- Share
-- Resource files
Any help would be much appreciated!
You would have to explicitly add an install rule for the external project libraries.
For example:
install(FILES ${OPENGL_LIBRARIES}
RUNTIME DESTINATION bin COMPONENT RuntimeLibraries
LIBRARY DESTINATION bin COMPONENT RuntimeLibraries
ARCHIVE DESTINATION Lib COMPONENT Development
)
Or you could use a specific library reference like ${OPENGL_gl_LIBRARY} instead of ${OPENGL_LIBRARIES}. See Modules/FindOpenGL.cmake for more details.

CMAKE: How to install the dependencies of a target

I am trying to install an executable using cmake. My real problem here is: how to install the executable and its dependencies.
Here an example:
I want to install one executable that depend on two libraries of my cmake and one 3rdparty (pre-compiled).
set(EXECUTABLE_NAME MyExecutable)
file(GLOB_RECURSE ${EXECUTABLE_NAME}_SOURCES *.cpp)
add_executable(${EXECUTABLE_NAME} ${${EXECUTABLE_NAME}_SOURCES})
target_link_libraries(${EXECUTABLE_NAME} MyLibrary1
MyLibrary2
${Boost_PROGRAM_OPTIONS_LIBRARY})
install(TARGETS ${EXECUTABLE_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
COMPONENT ${EXECUTABLE_NAME})
At the end I would like to find with this kind of CMakeLists.txt my two libraries, my executable and Boost_PROGRAM_OPTIONS_LIBRARY in the install folder and in my package.
What I have found, but I did not succeed to use:
BundleUtilities.cmake, here an example: https://cmake.org/Wiki/BundleUtilitiesExample.
As you can see it seems to do the perfect jobs, but it's complaining about "external prerequisites". I personally found that normal and I don't understand how to fix that. (Note: it succeeds in finding and copying the dependencies into a same folder before failing, Doc: https://cmake.org/cmake/help/v3.5/module/BundleUtilities.html)
GetPrerequisites.cmake. get_prerequisites is a lower level function that allow you to get the dependencies. The thing is, I don't any good way/best practice to use it.
Thanks,
I personally would make a library out of all of your dependencies with add_library(MyLibrary1 STATIC/SHARED/INTERFACE) and for boost most probably add_library(boost INTERFACE) followed by adding any include directories and linking the .as or .sos to them.
I would then link all my dependencies to MyExecutable as you have above. And at any point you can call the install function on all of these targets one at a time.
If you don't like repeating
install(TARGETS target
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
COMPONENT target
)
then you could break it out in to a function, something like this
function(INSTALL_CUSTOM target
install(TARGETS target
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
COMPONENT target
)
endfunction()
and then you could just call INSTALL_CUSTOM(MyLibrary1) or INSTALL_CUSTOM(boost).

How does CMake know which prefixes and suffixes to add to shared libraries?

I am trying to use INSTALL in CMake to copy some external binaries to an install directory. My code goes like:
SET(SimTK_SHARED_LIBS
SimTKsimbody
SimTKmath
SimTKcommon
SimTKmolmodel
)
INSTALL(TARGETS ${SimTK_SHARED_LIBS}
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
)
I get this error:
CMake Error at CMakeLists.txt:216 (INSTALL):
install TARGETS given target "SimTKsimbody" which does not exist in this
directory.
this is in spite of putting files called both libSimTKsimbody.so and (incorrectly) SimTKsimbody in the current directory as well as in the library directory.
Interestingly, this:
SET(SHARED_MMB_TARGET MMBlib)
ADD_LIBRARY(${SHARED_MMB_TARGET} SHARED
${MMB_LIBRARY_SOURCE_FILES}
${MMB_HEADER_FILES})
SET_TARGET_PROPERTIES(${SHARED_MMB_TARGET}
PROPERTIES
COMPILE_FLAGS "-DMMB_BUILDING_SHARED_LIBRARY"
PROJECT_LABEL "MMBlib (dynamic)")
TARGET_LINK_LIBRARIES(${SHARED_MMB_TARGET}
${SimTK_SHARED_LIBS_D}
${SimTK_SHARED_LIBS}
${OpenMM_SHARED_LIBS_D}
${OpenMM_SHARED_LIBS}
${SimTK_GENERAL_LIBS})
INSTALL(TARGETS ${SHARED_MMB_TARGET}
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
)
.. works fine. It installs libMMBlib.so in ${CMAKE_INSTALL_PREFIX}/lib as it should. Does this mean that INSTALL will only work for this if I issue ADD_LIBRARY and/or SET_TARGET_PROPERTIES? The SimTK_SHARED_LIBS are compiled separately, I really do not want to compile them here.
I have thought about using INSTALL FILES, and just writing code to process the library names for each operating system. However I am convinced that CMake has the means to do this for me easily and elegantly.
Many thanks
Sam
Yes, you should use INSTALL(FILES) for install external libraries files.
CMake uses CMAKE_SHARED_LIBRARY_PREFIX and CMAKE_SHARED_LIBRARY_SUFFIX as default prefix and suffix for libraries created with add_library(... SHARED), so you may expect these components from external library:
INSTALL(FILES /path/to/library/${CMAKE_SHARED_LIBRARY_PREFIX}SimTKsimbody${CMAKE_SHARED_LIBRARY_SUFFIX}
...)
Also you may use FIND_LIBRARY for automatic(and nice) check of your expectations about library suffix and prefix:
FIND_LIBRARY(SIMTK_SIMBODY_LIB
${CMAKE_SHARED_LIBRARY_PREFIX}SimTKsimbody${CMAKE_SHARED_LIBRARY_SUFFIX}
PATH /path/to/library)
INSTALL(FILES ${SIMTK_SIMBODY_LIB} ...)