What is the proper way to link CMake based project in Windows? - dll

Finally, after whole day spent, I've made my CMake based project to successfully compile project on Windows(I've been developing it in Linux) and it even links well together, perfect isn't it? Now I launch the program and boom, it's not able to find dll libraries.
So, The problem:
I have CMake project with library and executable inside, that executable is using project's library. I also have many third party libraries in project. It compiles and links well. When I try to launch it it prints error that project's library wasn't found. I've copied it to the executable's directory. Now it prints that 3rd party library wasn't found, I've copied all of them to exe's dir. Now it prints that gcc's library wasn't found, so I've added C:\MinGW\bin to the path and now it launches fine.
But I feel it's not the proper way. I'd like to spare my teammates(new) of that pain of launching.

Either link everything statically, or add necessary install() calls into your CMakeLists.txt. Install all needed libs into the same directory and run executable from there.
If you want to run executable from CMAKE_BINARY_DIR, you can
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} )
This would make CMake to put linked binaries into the same dir.
As for gcc runtime - there is no other way except copying dll or linking statically.

Related

Build gtest as shared library (dll) in CMake

I have never worked with CMake before, so please forgive any rookie mistakes. Most of the following working frame has been given to me by my project group.
The goal is to build GoogleTest into a .dll, to be used in different, indepentent parts of our project. I'm having troubles setting up CMake the right way.
The work-flow so far has been:
Clone gtest from git --> also downloads a CMake List file
Alter variables in CMakeCache.txt to have it produce a Code::Blocks project file
Compile the project file in Code::Blocks
So far, it produces a static library (.a files) that can be used in our project. I'm having troubles genereating .dll files.
Variables I have tried changing:
BUILD_SHARED_LIBS:BOOL=ON --> the files generated by Code::Blocks now have a .dll.a double extension
CMAKE_C_FLAGS and all the corresponding C++ flags where set to -DGTEST_CREATE_SHARED_LIBRARY=1 as given here
CMAKE_EXE_LINKER_FLAGS has been set to -shared to make the linker produce .dll files
I have worked my way through the GoogleTest documentation here and here but in both, building it into a .dll is merely a 2-sentence-topic.
As #Tsyvarev pointed out, the .dll files were created in a (very) different folder.

CMake TARGET_RUNTIME_DLLS is empty

I have git cloned, built (with MSVC for both Debug and Release) and then installed wxWidgets:
cmake -B build wxWidgets
cmake --build build --config <CONFIG>
cmake --install build --prefix my_install --config <CONFIG>
with <CONFIG> = Debug and <CONFIG> = Release.
Then I used the following CMake script to link against it, as suggested by the wiki:
cmake_minimum_required(VERSION 3.16)
project(Test)
add_executable(Test WIN32 Main.cpp)
# wxWidgets
SET(wxWidgets_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../thirdparty/my_install)
find_package(wxWidgets COMPONENTS core base REQUIRED)
include(${wxWidgets_USE_FILE})
target_link_libraries(Test PRIVATE ${wxWidgets_LIBRARIES})
# Copy runtime DLLs to the directory of the executable.
add_custom_command(TARGET Test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Runtime Dlls: $<TARGET_RUNTIME_DLLS:Test>"
)
My goal is to automatically copy the DLLs into the directory of the built executable, so that they can be found at runtime. For that I'm using the TARGET_RUNTIME_DLLS generator expression (follwing the sample code in the docs). In the code above, I only print out the expression at build time for testing purposes. The problem is that it is empty.
The approach worked for me before when installing and linking SDL, but SDL provides package configuration files which create imported targets, defining the DLL location(s) via IMPORTED_LOCATION_RELEASE or IMPORTED_LOCATION_DEBUG. For wxWidgets one is apparently supposed to use the FindwxWidgets.cmake script shipped with CMake, which sadly doesn't define the produced binaries. Maybe that's why TARGET_RUNTIME_DLLS isn't populated.
Does anyone know, either how to get TARGET_RUNTIME_DLLS filled or how to obtain the list of built wxWidgets DLLs for the current configuration (Release/Debug) post build copying?
Thanks a lot in advance!
I am dealing with a similar problem.
First sanity checks:
You have to work on windows platform otherwise this feature does not
work.
Your Cmake is 3.21 or above
Next comes fuzzy part. I think the library that you are trying to include have to be a Shared Imported library and you have to set a set_target_properties for IMPORTED_IMPLIB which is a path to a .lib file of sort (dll import library, I think it is called) So you have to make sure that it is all set in the package library that you trying to link with your executable.
If you have those dll avaiable and you just want to use them and not actually build them then you can write your own cmake script that will do just what I said above. Then you can include that cmake file in your project and then link against your app.
Note: I also work on similar issue right now and what I just said have not been working very reliably. I got some dlls to be copied and some do not.
Edit:
Cmake docs give a more detailed explanation on how this library setting should look like if you use find_package feature.
Found here: https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries
An UNKNOWN library type is typically only used in the implementation
of Find Modules. It allows the path to an imported library (often
found using the find_library() command) to be used without having to
know what type of library it is. This is especially useful on Windows
where a static library and a DLL's import library both have the same
file extension.

How to get CMake to embed a private framework into a macOS app bundle?

target_link_libraries links private frameworks fine but it doesn't have a way to copy the frameworks into the app bundle's Frameworks directory. It also doesn't have a way to then update the executable's path to the framework.
So essentially I need CMake to:
Link with a private dylib.
Copy that dylib into the app bundle's Frameworks directory.
Update the executable's path to the dylib.
I decided to write my own rpaths to the final executable. To prevent CMake from writing build rpaths set CMAKE_SKIP_BUILD_RPATH. This needs to be set before add_executable.
set(CMAKE_SKIP_BUILD_RPATH TRUE)
Then I copy all the dylibs I want to embed into the built app bundle's Frameworks directory. In this case I'm copying MoltenVK which is being stored in the project. ${PROJECT_NAME} is the executable name.
set(APP_BUNDLE_CONTENTS_DIR "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.app/Contents")
set(APP_BUNDLE_FRAMEWORKS_DIR "${APP_BUNDLE_CONTENTS_DIR}/Frameworks")
file(GLOB VULKAN_DYLIB_PATHS "${CMAKE_SOURCE_DIR}/external/vulkan/builds/mac/*")
target_link_libraries(${PROJECT_NAME} ${VULKAN_DYLIB_PATHS})
file(COPY ${VULKAN_DYLIB_PATHS} DESTINATION ${APP_BUNDLE_FRAMEWORKS_DIR})
Then I add an rpath to the executable as a post build command.
add_custom_command(TARGET ${PROJECT_NAME}
POST_BUILD COMMAND
install_name_tool -add_rpath "#executable_path/../Frameworks/"
"${APP_BUNDLE_CONTENTS_DIR}/MacOS/${PROJECT_NAME}")
This works for building and debugging with CMake. This won't work when generating an Xcode project. Hopefully I'll find a better cleaner way, but this works for now.

CMAKE - makefile target for a library

I'm currently changing the build system on my project, from gnu makefiles to cmake (that generate makefiles).
My project generates several libraries (.lib), and several executables (.exe).
Currently i generate the makefiles using the following command :
cmake -G "Unix Makefiles" .. -DCMAKE_BUILD_TYPE=Debug
The generated makefiles contain an all target, as well as a target for every executable (compiled as such with the add_executable cmake directive), so i can compile a subset of the project (which saves a lot of time) : make executable_1; make executable_2 and so on.
However, there is no target for the libraries (compiled as such with the add_library cmake directive) so i cannot do make library_1 for example. I want to do this because it would save a lot of time.
I tried to add a dummy executable in the library's cmake, and link the library to this executable (which only contains a main without actually using library_1's code).
add_library(library_1 test.cpp)
add_executable(dummy_exe dummy_main.cpp)
target_link_library(dummy_exe library_1)
It does add a target for dummy_exe but does not build the library because it does not actually need to link any of the library_1's code.
This was a workaround attempt anyway, and i'd rather just call make library_1 after all. Is there any way to add a makefile target for a library using cmake ?
As answered by w-m and Fred, CMAKE indeed create a target for libraries in the Makefile.
I was trying to build the library with the cmake subproject name of the library instead of the library name.
make help was indeed of big help to find this issue, as it lists everything that can be built.

Use external DLL in cmake build

I'm working on the cmake scripts for my project and I've run into a problem:
My project uses a 3rd party library (FreeImage), which has its own Makefile-based build system. I can build FreeImage just fine by simply running "make" (I'm using gnuwin32), which will build FreeImage using MinGW and produce:
FreeImage.lib
FreeImage.dll
Now my problem is twofold:
I want to execute "make" from my cmake script.
I want to link to the import lib (FreeImage.lib), and also make sure the DLL gets copied to the correct place so the EXE will run.
I know how to link to the LIB file, but I'm lost on the rest.
The folder structure is like this:
MyProject # main directory
MyProject/Libs/FreeImage # FreeImage root directory
MyProject/Libs/FreeImage/Dist # This is where FreeImage outputs go (LIB and DLL)
BTW: I'm running on Windows 7. I plan to build my project both with MSVC and MinGW.
Thanks!
EDIT:
I'm now trying to use ExternalProject_Add like so:
ExternalProject_Add(
FreeImage
PREFIX ./Libs/FreeImage
URL ./Libs/FreeImage
BUILD_COMMAND make
)
This gets me part of the way there, but doesn't totally work... it tries to configure things for me and tries to use nmake... ugh
In my opinion, there are two options:
In case you have put your FreeImage sources in your projects' source-tree, the easiest option may be to use the execute_process() command. Assuming FreeImage is in your projects' source-tree in "3rdparty/FreeImage/" you can do something like,
execute_process( COMMAND make WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/3rdParty/FreeImage )
Optionally, you can copy the dll from 3rdParty/FreeImage/bin into you own bin directory. And then you can write a FreeImageConfig.cmake for importing the library:
add_library( FreeImage IMPORTED )
set_target_properties( FreeImage PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/3rdParty/FreeImage/lib )
...
The other option is to make use of the ExternalProject module. You can also take a look at this article from Kitware for an overview of this module. In essence, you specify the full chain of commands needed to get the source, configure the build, build the source and install it. All in your own CMakeLists.txt