CMake - Link against exe on Windows - c++

I'm trying to make a plugin system for my application, and thus each plugin will need to link with my main application. This is fine on Linux and macOS, as I can just set the ENABLE_EXPORTS property of my executable target (set_target_properties(${PROJECT_NAME} PROPERTIES ENABLE_EXPORTS 1), and plugins will link just fine. On Windows however, clang++ yells at me that it can't find libws2editor.dll.a.
clang++.exe: error: no such file or directory: 'ws2editor/libws2editor.dll.a'
Upon looking over the CMake docs, it says "For DLL platforms an import library will be created for the exported symbols and then used for linking." - This import library file (presumably the .dll.a) never seems to be created though.
So how can I get the CMake build on Windows to create this file, or otherwise link with an executable?

Looks like I can use ar to generate the .a file for me, regardless of generator - plugins seem to link and load just fine when doing this. Awesome! :)
if(WIN32)
#Invoke ar to generate a .dll.a from the .obj files, required to link plugins
add_custom_command(TARGET ${PROJECT_NAME} PRE_LINK
COMMAND sh -c "${CMAKE_AR} cr lib${PROJECT_NAME}.dll.a $$(find . -name '*.obj' -printf '%p ')"
COMMENT "Generating lib${PROJECT_NAME}.dll.a for external linking"
)
#Also add the install command for libws2editor.dll.a
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${PROJECT_NAME}.dll.a DESTINATION bin)
endif(WIN32)

Related

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)

cmake + cpp: No such file or directory

I've I'm trying to build this "Hello World" wxWidgets example on Linux, using the following cmake script:
cmake_minimum_required (VERSION 2.6)
project (wxL)
find_package(wxWidgets 3.0.0 REQUIRED
COMPONENTS base core net xml html adv qa richtext
)
file(GLOB SOURCES "src/*.cpp")
add_executable(wxL ${SOURCES})
Building the project yields this error:
src/wxL.cpp:3:10: fatal error: wx/wxprec.h: No such file or directory
The file specified in the include, wx/wxprec.h can be found on disk at this location:
/usr/include/wx-3.0/wx/wxprec.h
Furthermore, another program that I have built from source includes the same file (also using cmake) and builds just fine.
So, how do I use cmake to tell the compiler that the file should be included from somewhere in the system directories?
I know I'm missing something basic, but I can't figure out what.
Although you've found the package, your executable does not know anything about it.
For the executable to compile correctly, it needs to find header files for your package together with the .so / .a files. Following example should get you started:
include_directories(${wxWidgets_INCLUDE_DIRS})
add_executable(wxL <add-source-files-here>)
target_link_libraries(wxL ${wxWidgets_LIBRARIES}) // links wxWidgets libraries to your executable
Please note that using glob is not a recommended way of adding source files to your project.

dyld not loading Ogre library

I am trying to setup an environment to develop an Ogre3D application. I have manually compiled Ogre into folder /opt/Ogre3D/ogre-1.11.5/build and created a CMake project in CLion with this content:
cmake_minimum_required(VERSION 3.13)
project(sample)
set(CMAKE_CXX_STANDARD 14)
set(OGRE_DIR /opt/Ogre3D/ogre-1.11.5/build/sdk/cmake)
# specify which version and components you need
find_package(OGRE 1.11 REQUIRED COMPONENTS Bites RTShaderSystem)
# copy resource.cfg next to our binaries where OGRE looks for it
file(COPY ${OGRE_CONFIG_DIR}/resources.cfg DESTINATION ${CMAKE_BINARY_DIR})
add_executable(sample main.cpp)
target_link_libraries(sample ${OGRE_LIBRARIES})
when I try to run it, compilation is OK but then it can't execute it:
/Users/diego/CLionProjects/ogre/sample/cmake-build-debug/sample
dyld: Library not loaded: #executable_path/../Frameworks/OgreBites.framework/Versions/1.11.5/OgreBites
Referenced from: /Users/diego/CLionProjects/ogre/sample/cmake-build-debug/sample
Reason: image not found
Process finished with exit code 6
I have looked at otool -l /opt/Ogre3D/ogre-1.11.5/build/lib/macosx/OgreBites.framework/Versions/1.11.5/OgreBites and there is a command LC_ID_DYLIB with the name #executable_path/../Frameworks/OgreBites.framework/Versions/1.11.5/OgreBites, which matches the path given in the runtime error. However I don't know which step to take now as I have few experience with native library resolution on macOS.
Update:
Executing the command install_name_tool makes the linker find the library, but then it fails with the next one. I suppose/hope there is an option in CMake to pass it to the compiler so the binary files created during Ogre's compilation do not use the #execute_path directive?
I'm faced with the same problem, when using clion to build ogre in macos.
I found the symbolic links were invalid in the directory cmake-build-debug/bin/SampleBrowser.app/Contents/Frameworks.
I guess these symbolic links should point to
these frameworks int the cmake-build-debug/lib/macosx. So I modified the file where executed ln to create these symbolic links.
In the file Samples/Browser/CMakeLists.txt, change
set(OGRE_OSX_BUILD_CONFIGURATION "${CMAKE_OSX_SYSROOT}/$(CONFIGURATION)")
into
set(OGRE_OSX_BUILD_CONFIGURATION "macosx")
And clean and rebuild, then the problem will disappear.

Linking runtime library for test with cmake

Is there any simple way to link at runtime a locally built library to a test with CMAKE?
For example:
enable_testing()
add_executable(Test test/Test.cpp)
target_link_libraries(Test -L../lib/libzmq/build/lib/ zmq)
add_test(
NAME TestClientZmq
COMMAND "LD_PRELOAD=../lib/libzmq/build/lib/libzmq.so Test")
Running the test will complain about the missing library at runtime:
error while loading shared libraries: libzmq.so.4.2.0: cannot open shared object file: No such file or directory
I can either:
Set LD_PRELOAD when running ctest
Write a wrapper script which does this and then calls the executable (what I have currently)
I would prefer to do everything in cmake though, since I think it's best to keep all this configuration in a single place to avoid bugs in the future.
Add
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
to your CMakeLists.txt. As explained in this wiki article.
After build, use the below command to make sure the RPATH is properly set:
objdump -x Test | grep RPATH

Cmake external library .a

I have an external library here:
${PROJECT_SOURCE_DIR}/thirdparty/yaml-cpp/
It is made by a Makefile: thirdparty/Makefile. I am executing that makefile like so:
add_custom_target(
yaml-cpp
COMMAND make
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/thirdparty
)
I am then attempting to link the library, which builds to thirdparty/yaml-cpp/build/libyaml-cpp.a. This is the part that is not working:
target_link_libraries(load_balancer_node ${CMAKE_SOURCE_DIR}/thirdparty/yaml-cpp/build/libyaml-cpp.a)
I get the error:
Target "yaml-cpp" of type UTILITY may not be linked into another target.
One may link only to STATIC or SHARED libraries, or to executables with the
ENABLE_EXPORTS property set.
How do I execute that makefile and link the .a file?
So it makes sense that cmake can't figure out the dependencies here: it would have to parse the makefile and find the output. You have to tell it the output someone. Nearest I can figure, the best way to do this is to use a custom_command rather than a custom target:
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/thirdparty/yaml-cpp/build/libyaml-cpp.a
COMMAND make
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/thirdparty)
add_custom_target(
yaml-cpp
DEPENDS ${CMAKE_SOURCE_DIR}/thirdparty/yaml-cpp/build/libyaml-cpp.a)
...
add_dependencies(load_balancer_node yaml-cpp)
target_link_libraries(load_balancer_node ${CMAKE_SOURCE_DIR}/thirdparty/yaml-cpp/build/libyaml-cpp.a)
I was having linker troubles though (stupid windows machine), but cmake worked and made the libraries before trying to link.