My enviorment: Windows 10 + MinGW
I m a newer to CMake, and I try to figure out how to import 3rd libs to my project, my trial project structure is list as follow, which location is: D:/CodeDraft/helloworld
D:.
│ CMakeLists.txt
│ main.cpp
│ run_cmake.ps1
│
├─3rdparty
│ └─fmt_x64-mingw-dynamic
│ │ BUILD_INFO
│ │ CONTROL
│ │
│ ├─bin
│ │ libfmt.dll
│ │
│ ├─debug
│ │ ├─bin
│ │ │ libfmtd.dll
│ │ │
│ │ └─lib
│ │ │ libfmtd.dll.a
│ │ │
│ │ └─pkgconfig
│ │ fmt.pc
│ │
│ ├─include
│ │ └─fmt
and main.cpp:
#include <fmt/core.h>
int main()
{
fmt::print("Hello World!\n");
return 0;
}
As you can see I download fmt libs from vcpkg, for some reason I decide to build project by native way instead of using vcpkg function.
according to Importing and Exporting Guide and reference some other projects, I try to link fmt dll on my CMakeLists.txt like this:
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
message("CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}")
add_executable(HelloWorld main.cpp)
add_library(fmt SHARED IMPORTED)
set_property(TARGET fmt PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/bin/libfmt.dll)
target_include_directories(fmt INTERFACE ${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/include)
target_link_libraries(HelloWorld fmt)
add_custom_command(TARGET HelloWorld POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy -t $<TARGET_RUNTIME_DLLS:HelloWorld> $<TARGET_FILE_DIR:HelloWorld>
COMMAND_EXPAND_LISTS
)
and my build script is : run_cmake.ps1
cmake -G "MinGW Makefiles" -B build
cd build
make
.\HelloWorld.exe
cd ..
I run the run_cmake.ps1, the cmake compile is success, but when it cames to make
it throw error and say fmt lib is not found:
CMAKE_SOURCE_DIR: D:/CodeDraft/helloworld
-- Configuring done (0.2s)
CMake Warning (dev) in CMakeLists.txt:
Policy CMP0111 is not set: An imported target missing its location property
fails during generation. Run "cmake --help-policy CMP0111" for policy
details. Use the cmake_policy command to set the policy and suppress this
warning.
IMPORTED_IMPLIB not set for imported target "fmt".
This warning is for project developers. Use -Wno-dev to suppress it.
-- Generating done (0.1s)
-- Build files have been written to: D:/CodeDraft/helloworld/build
make[2]: *** No rule to make target 'fmt-NOTFOUND', needed by 'HelloWorld.exe'. Stop.
make[1]: *** [CMakeFiles\Makefile2:82: CMakeFiles/HelloWorld.dir/all] Error 2
make: *** [Makefile:90: all] Error 2
For hours of searching I still not idea the causes, I also try compile as the same way on ubuntu, strangely it works:
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
add_executable(HelloWorld main.cpp)
add_library(fmt SHARED IMPORTED GLOBAL)
set_target_properties(fmt PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-linux-dynamic/lib/libfmt.so)
target_include_directories(fmt INTERFACE ${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-linux-dynamic/include)
target_link_libraries(HelloWorld fmt)
I definitely sure not dll itself problem because I'm successful compile and run the project with g++ native command:
g++ -g .\main.cpp -o .\main.exe -I.\3rdparty\fmt_x64-mingw-dynamic\include\ -L.\3rdparty\fmt_x64-mingw-dynamic\lib\ -lfmt
# then copy the libfmt.dll along with the main.exe
either not path problem, because I compile and run successfully to write CMakesList.txt another way, the path of include and lib is identical:
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
message("CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}")
include_directories(${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/include)
link_directories(${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/bin) # -Lpath
link_libraries(fmt) #-lfmt
add_executable(HelloWorld main.cpp)
add_custom_command(TARGET HelloWorld POST_BUILD #-for copy libs in windows
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/bin/libfmt.dll
${CMAKE_SOURCE_DIR}/build)
so what's wrong?
On Windows a .dll
file is used only at runtime (when your executable is run). At build time (while creating an executable), the linker uses .lib
file.
When represent a library with SHARED IMPORTED library target, on Windows:
IMPORTED_LOCATION
should contain the path to the .dll
fileIMPORTED_IMPLIB
property should contain the path to the import library (.lib
file).In the warning message CMake tells you, that you forgot to set IMPORTED_IMPLIB
property. Without that property the linker doesn't know which library to use for linking.
Correct:
add_library(fmt SHARED IMPORTED)
set_property(TARGET fmt PROPERTY
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/bin/libfmt.dll
IMORTED_IMPLIB ${CMAKE_SOURCE_DIR}/3rdparty/fmt_x64-mingw-dynamic/lib/libfmt.lib
)