CMake find_library can't find an existing library on MSVC - cmake

I made a project and tried to build it under GCC (Linux) and MinGW (Windows) using CMake. Now I'm trying to do the same under Visual Studio 2019 (for reasons) and it seems that CMake that is shipped with VS can't find libraries installed with MSVC.
I'm using a script which unfortunately I can't find again on the Net, so I can't give you a link to it. But I tried to isolate what is causing the problem. So, here is the code:
if(MY_LIB_PATH)
set(MYLIB_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
endif()
find_library(MY_LIBRARY
NAMES myLibrary
HINTS
ENV MY_ENV
${MYLIB_NO_DEFAULT_PATH_CMD}
PATH_SUFFIXES lib lib/x64
PATHS ${MY_LIB_PATH}
DOC ""
)
(the code is much complicated than that, but that is what it looks after all variable substitutions)
If I don't set the MY_LIB_PATH variable it can't find the library (which is located in the lib/x64 folder in the MSVC installation folder). But when I call CMake like this:
cmake "-DMY_LIB_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\lib\x64"
it "miraculously" finds it.
Yes it works but...wasn't CMake made to avoid writing all that path in the first place? Besides, there is yet another problem: there are many such libraries in my project, all of which use the same above code for finding, and I have to write all that path multiple times, so CMake can find them.
Either the authors of my CMake script did something wrong or I installed my libraries not where CMake is expecting them.

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.

Setting Cmake Library paths without Editing CmakeLists

Goal: To set Cmake Paths without having to edit the CMakeLists.txt file.
In Linux, using find_library() in Cmake is enough to find a library installed with apt.
In Windows, Cmake is unable to find it automatically.
Note: Please treat sqlite3 as any library.
What is the proper method to set the library paths which cmake searches for my library files without having to edit CMakeLists?
Note: I have samlib compiled to a static library file and placed in some directory away from the project itself.
I have tried the following on Linux and Windows.
cmake_minimum_required(VERSION 3.0.0)
project(SampleProj VERSION 0.1.0)
find_library(samlib NAMES samplelib)
add_executable(SampleProj src/main.cpp)
target_link_libraries(SampleProj ${samlib})```
Try to use CMAKE_LIBRARY_PATH
Semicolon-separated list of directories specifying a search path for the find_library() command. By default it is empty, it is intended to be set by the project. See also CMAKE_SYSTEM_LIBRARY_PATH and CMAKE_PREFIX_PATH.
src: https://cmake.org/cmake/help/latest/variable/CMAKE_LIBRARY_PATH.html
set CMAKE_GENERATOR=Visual Studio 15 2017 Win64
cmake -H. -Bbuild -G "%CMAKE_GENERATOR%" "-DCMAKE_PREFIX_PATH=path_to_samlib"

CMake External Library Linking?

It seems cmake can't determine which libraries can be used with the current compiler or rather I want cmake to only use libraries that have been compiled with the same compiler.
I am using find_library to find the needed libraries but it seems to be unable to determine if the library is actually usable. It managed to find the library by name but it was using the ".lib" extension when I was making a configuration for MinGW. Do I have to create folders for every compiler I compile libraries for and add if statements for each compiler in my script ? That just seems counter intuitive to what I believed find_library would be capable of. Perhaps I am misusing it ? Anyone have any better ideas ?
It seems you're a bit confused: you're right when you suggest that you need different libraries for MinGW and Visual Studio on Windows. But you're wrong when saying that .lib files can't be used by MinGW. Both Visual Studio and MinGW use .lib files to link to libraries on Windows.
The find_library command purpose is only to find libraries. Nothing more, so it's doing its job here.
If you want to make sure that the libraries found can be used by your compiler, you'll have to check that those libraries can be used by your compiler using try_compile:
find_library(YOURLIB_LIBRARY yourlib)
if (YOURLIB_LIBRARY)
try_compile(YOURLIB_WORKS
bindir
somefile.c
LINK_LIBRARIES ${YOURLIB_LIBRARY})
if (YOURLIB_WORKS)
# do something with your library
else()
# warn the user of stop the configuration process
endif()
endif()

llvm's cmake integration

I'm currently building a compiler/interpreter in C/C++.
When I noticed LLVM I thought it would fit greatly to what I needed and so I'm trying to integrate LLVM in my existing build system (I use CMake).
I read this bout integration of LLVM in CMake. I copy and pasted the example CMakeLists.txt, changed the LLVM_ROOT to ~/.llvm/ (that's where I downloaded and build LLVM and clang) and it says it isn't a valid LLVM-install. Best result I could achieve was the error message "Can't find LLVMConfig" by changing LLVM_ROOT to ~/.llvm/llvm.
My ~/.llvm/ folder looks like this:
~/.llvm/llvm # this folder contains source files
~/.llvm/build # this folder contains object, executable and library files
I downloaded LLVM and clang via SVN. I did not build it with CMake.
Is it just me or is something wrong with the CMakeLists.txt?
This CMake documentation page got rotted, but setting up CMake for LLVM developing isn't different from any other project. If your headers/libs are installed into non-standard prefix, there is no way for CMake to guess it.
You need to set CMAKE_PREFIX_PATH to the LLVM installation prefix or CMAKE_MODULE_PATH to prefix/share/llvm/cmake to make it work.
And yes, use the second code snippet from documentation (under Alternativaly, you can utilize CMake’s find_package functionality. line).