CMake linking against shared library on windows: error about not finding .lib file
Ah, my problem was I forgot to include a __declspec(dllexport) in suitable places when building the library (can you tell I don't do windows programming a lot?).
Cmake Linking Shared Library: No such file or directory when include a header file from library
You have a couple of issues here.
Propagating headers to users of your target:
Whilst you've added the include file to your library target, you need to let consumers of your library target know how to find the header.
As such, when your app myapp
links against your library target test
, you need to tell cmake to add ./include
to myapp's
include search path.
There is a special cmake variable, ${CMAKE_CURRENT_LIST_DIR}
which resolves to the path to the directory in which the current CMakeLists.txt
being processed is.
In your instance, that is the parent folder of both src
and include
.
./ <-- ${CMAKE_CURRENT_LIST_DIR} is this directory
+--- CMakeLists.txt
+--- src/
| +---Test.cpp
| +---ITest.cpp
+--- include/
+---Test.hpp
+---ITest.hpp
In order to tell cmake to add a path to its include search path you use target_include_directories
For this the path will then be ${CMAKE_CURRENT_LIST_DIR}/include
So the syntax you'd be looking for is:
target_include_directories(test PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
Note that this means you don't have to add "include/iTest.hpp"
and "include/Test.hpp"
to your SRC_LIST
glob, as the compiler will be able to find them from the above target_include_directories
Linking to your test library:
Now that you've created your library and added the include directories, to actually use it in your app, you should again use target_link_libraries
, but don't specify the path to the generated .so
file, instead refer to the name of the library target you created, test
target_link_libraries(myapp test)
Now myapp
will know how to find Test.hpp
because it will get that information from the "dependency link" you've created between myapp
and test
As such, assuming the following directory structure, the following CMakeLists.txt files may work
src/
+--- library/
| +--- < sources for your shared library >
+--- app/
+--- < sources for your application >
src/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(myapp)
add_subdirectory(library)
add_subdirectory(app)
src/library/CMakeLists.txt
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}
-std=c++11
-pthread
-O3
-Wall
-ftree-vectorize
-ffast-math
-funroll-loops")
find_package(OpenCV REQUIRED)
add_library(test SHARED "src/iTest.cpp src/Test.cpp")
target_link_libraries(test ${OpenCV_LIBS}) // link opencv libs to libtest.so
target_include_directories(test PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
src/app/CMakeLists.txt
add_executable(myapp main.cpp)
target_link_libraries(myapp test)
missing .lib file when creating shared library with cmake and visual studio 2019 generator
Faced the same problem, I found the solution here: for Visual Studio to export symbols in a .lib
file besides the .dll
library, you need to set this in your CMake (version>= 3.4) script:
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
Note that the .lib
file created this way is a small size file and is not a static library.
CMake manual
Cmake cannot find library using link_directories
Do not use link_directories
like this in CMake.
This is a common beginner's mistake, as many other build environments work like this, but in CMake it's just asking for trouble. Even the official documentation specifically advises against it:
Note that this command [
link_directories
] is rarely necessary. Library locations returned
byfind_package()
andfind_library()
are absolute paths. Pass these
absolute library file paths directly to thetarget_link_libraries()
command. CMake will ensure the linker finds them.
So instead, always pass absolute paths to target_link_libraries
and use find_library
to resolve the link directory:
find_library(PROTOBUF_LIBRARY protobuf HINTS /usr/lib/x86_64-linux-gnu)
target_link_libraries(test PUBLIC ${PROTOBUF_LIBRARY})
This has the huge benefit that you will probably get a diagnostic at CMake configure time if the expected library cannot be found, instead of a random linker error at compile time. Also, this allows the user to specify a library location via the GUI if the target machine has a non-standard directory layout.
So if it doesn't work right away, be sure to check the result of the find_library
call and consult the official documentation to track down why it doesn't find your library as intended.
CMake link shared library on Windows
There are differences between dynamic library linking on different platforms which also needs some additional code. The good news is, that CMake can help you with this. I found the following blog post by Gernot Klingler very useful:
- Creating and using shared libraries with different compilers on different operating systems
In short you need some "export prefix" defined for whatever is declared in m.h
. Otherwise the build process will not generate an "import library" for statically linking named m.lib
(see also CMAKE_IMPORT_LIBRARY_SUFFIX
).
Here is your code with the modifications needed:
m.h
#include "m_exports.h"
int M_EXPORTS m();
m.c
#include "m.h"
#include <stdio.h>
int m(){
printf("Hello,m!\n");
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
include(GenerateExportHeader)
PROJECT("app1")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}")
ADD_LIBRARY(m SHARED m.c m.h m_exports.h)
GENERATE_EXPORT_HEADER(m
BASE_NAME m
EXPORT_MACRO_NAME M_EXPORTS
EXPORT_FILE_NAME m_exports.h
STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC)
ADD_EXECUTABLE(myexe main.c)
TARGET_LINK_LIBRARIES(myexe m)
Additional References
- GenerateExportHeader macro
- cmake and GenerateExportHeader
- How do I get CMake to create a dll and its matching lib file?
- MSDN: Walkthrough: Creating and Using a Dynamic Link Library (C++)
Linking with CMakeLists: ld cannot find library
That's because when linking, the linker doesn't look in the current directory but only in a set of predefined directories.
You need to tell CMake where the library is, for example by giving the full path to the library in the target_link_library
command, or adding it as an imported library.
Related Topics
C++ Remove Punctuation from String
Why Isn't C/C++'s "#Pragma Once" an Iso Standard
Logical And, Or: Is Left-To-Right Evaluation Guaranteed
C++ Typedef Interpretation of Const Pointers
Avoiding the Tedium of Optional Parameters
Determine Process Info Programmatically in Darwin/Osx
Efficient Bitwise Operations for Counting Bits or Find the Right|Left Most Ones
Writing Directly to Std::String Internal Buffers
Are Compound Literals Standard C++
Meaning of (Number) & (-Number)
Virtual Destructor and Undefined Behavior