Why doesn't my generated project create an import library? [duplicate] - c++

This question already has answers here:
Error LNK1104: cannot open file 'Debug\MyProjectLib.lib'
(2 answers)
Closed 10 days ago.
I have this cmake:
cmake_minimum_required (VERSION 3.20)
project (DllTest)
if (MSVC)
add_compile_definitions(UNICODE _UNICODE)
endif()
add_library(mydll SHARED dllmain.cpp)
add_executable(test_dll testmain.cpp)
target_link_libraries(test_dll PUBLIC mydll)
when I generate projects using this cmake test file and compile the code, I am getting this error:
Error LNK1104 cannot open file 'Debug\mydll.lib'
I searched all of the build directories and I can not find any mydll.lib.
How can I create a Dll and linked it to another project using cmake?

According to Create dlls on Windows without declspec() using new CMake export all feature, the author said:
A shared library on Windows known as a DLL (dynamic linked library)
requires changes to the source code or an explicit listing of all the
symbols that the dll will export. The compilers on Linux/UNIX have
the ability to export all symbols in a shared library automatically.
On Windows, you must either use compiler directives __declspec(import)
and __declspec(export) to declare which symbols are exported/imported
from a shared library, or you must create a module definition text
file (.def) with a list of all the symbols you want to export and pass
that file to the linker. The feature is implemented in CMake via a new
target property, WINDOWS_EXPORT_ALL_SYMBOLS. When enabled, this
property causes CMake to automatically create a .def file with all
symbols found in the input .obj files for a SHARED library on Windows.
The .def file will be passed to the linker causing all symbols to be
exported from the DLL.
So add set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) in your CMakeLists or run cmake -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE -DBUILD_SHARED_LIBS=TRUE , the link error will be fixed.

Related

What does cmake do with Unnecessary links

I'm cleaning/refactoring a quite old project and I realized they made the mistake(?) of adding unnecessary links to the targets in all the CMakeLists.txt files:
LIST(APPEND ${PROJECT_NAME}_LIBRARIES RecursiveLy_generated_list_with_unnecessarystuff)
target_link_libraries(sample PUBLIC ${${PROJECT_NAME}_LIBRARIES})
I replaced the list by one that contains only the necessary links and the compilation time got noticeably reduced.
So I'm wondering what does cmake do when the symbols of a library that was linked are not used?
I also cleaned the include directories (ALL the .h files of the project were recursively added (many not needed)), did cmake think the symbols were used because they appeared in the headers even if this headers were not #included ?
What does cmake do with Unnecessary links
Passes proper command line options to the compiler.
what does cmake do when the symbols of a library that was linked are not used?
Nothing. CMake is not even aware that symbols of a library are or are not used. CMake does not link your code, compiler does.
did cmake think the symbols were used because they appeared in the headers even if this headers were not #included ?
No, CMake is unaware of what symbols are used where. CMake is unaware of the content of header files. CMake creates a list of commands to run. What commands to run depends on what is written in CMakeLists.txt.

Cmake: how to include external shared library to static library

I am trying to include an external dll to the current cmake project.
External project ext1 package structure
-- include //headers
-- lib // which has both dll, lib
In the current project,
I am including the libraries of the external ext1 package
find_package(ext1 3.1.2 REQUIRED)
include_directories(${ext1 _INCLUDE_DIRS})
link_directories(${ext1 _DIR}/lib)
But with the above inclusion, Cmake is only taking the static library from the package.
I also tried invoking linking the dll into the current package. But faced fatal error with trying to open a corrupt dll file.
link_directories(${ext1 _DIR}/lib/a.dll)
Please let me know further how to fix it.

CMake add_library using the MODULE keyword doesn't create PDB file

In my CMake build using ninja as the back-end, DLLs with no exported symbols are always re-linked, so I use the MODULE keyword with add_library for those DLLs as recommended here and in the add_library docs.
But now those DLLs do not have corresponding PDB files created with them (or perhaps they are being generated in the object directory with the default name, rather than in the output directory with the library name).
The PDB_NAME docs imply that it only applies to executables and SHARED libraries (no mention of MODULEs):
Output name for the ... .pdb file generated by the linker for an
executable or shared library target.
How can I get the PDB file created in the expected location with the right name for a MODULE library?
I went back to using SHARED libraries and added a dummy symbol to be exported from each such library. This way the cmake files stay consistent with all the other libs.

Linking both third party precompiled dynamic and static libaries in Windows

Lately, I have been using cmake as a generator for my projects. I have successfully generated many vtk and other application projects. However, I now face a problem when trying to link both dynamic and static precompiled libraries. In particular, I have been given some dynamic precompiled third party dlls along with their respective .lib files. Furthermore, I am trying to link some static precompiled libraries (only .lib files) to my project so as to check the software licences.
Let say that my project is called test_example and I have some precompiled dynamic libraries in libs directory. The structure of my project directory is:
Test_example
-/include
-/libs
-/build
-CMakeLists.txt
The CMakeLists.txt for linking the dynamic libaries has the following content:
cmake_minimum_required(VERSION 2.8.9)
project (test_example)
set(CMAKE_BUILD_TYPE Release)
#For the shared libraries:
set (PROJECT_LINK_LIBS dynamic_1.dll dynamic_2.dll )
set (PROJECT_LINK_DIR ${test_example_SOURCE_DIR}/libs/)
set (PROJECT_INCLUDE_DIR ${test_example_SOURCE_DIR}/include/)
link_directories(${PROJECT_LINK_DIR})
include_directories(${PROJECT_INCLUDE_DIR})
add_executable(test_example test_example.cpp)
target_link_libraries(test_example ${PROJECT_LINK_LIBS})
When I generate the project with this cmake lists, I can successfully use methods from the precompiled dlls. However, I have not found a way to link against my static libraries, as well. Let say I have one static library which is called test_licence.lib. Should I drop it in the libs folder as well and simply refer to it like I do with the dynamic? When I do so and when opening my project solution in Visual Studio, I can see that both dynamic and static libraries have been added to Linker-->Input-->Additional DEpendencies. However, when I am trying to build the project, I have unresolved external dependencies which are methods from the static lib.
Does any of you have any idea what would be the most efficient way to accomplish that? Many thanks in advance!
There is a couple of issues here.
Unlike to what you may be used to from VS, CMake prefers absolute paths for linking, instead of setting a link directory and giving the relative path.
Also, you do not link against .dll files. Dlls are loaded at runtime, not at link time. Many dlls are shipped with import libraries (with a .lib ending), that handle the runtime loading automatically for you. These are the ones you should link against.
Also try not to hardcode libraries in CMake code. The problem here is that if something goes wrong, you end up with a cryptic linker error. You should use find_library instead, which will usually make CMake complain early if something is off.
A cleaner version of your CMake script would be something like
cmake_minimum_required(VERSION 2.8.9)
project (test_example)
# note setting the build type does nothing on a visual studio build
# and should probably be left to the user for other generators
set(CMAKE_BUILD_TYPE Release)
#For the shared libraries:
# this call will succeed if it finds a dynamic_1.lib file
find_library(DYNAMIC_LIB1 dynamic_1 HINTS ${test_example_SOURCE_DIR}/libs)
if(NOT DYNAMIC_LIB1)
message(FATAL_ERROR "Library dynamic_1 was not found!")
endif()
find_library(DYNAMIC_LIB2 dynamic_2 HINTS ${test_example_SOURCE_DIR}/libs)
if(NOT DYNAMIC_LIB2)
message(FATAL_ERROR "Library dynamic_2 was not found!")
endif()
# for the static libraries:
# basically the same; again this looks for a static_1.lib file
find_library(STATIC_LIB1 static1 HINTS ${test_example_SOURCE_DIR}/libs)
if(NOT STATIC_LIB1)
message(FATAL_ERROR "Library static_1 was not found!")
endif()
set (PROJECT_INCLUDE_DIR ${test_example_SOURCE_DIR}/include/)
include_directories(${PROJECT_INCLUDE_DIR})
add_executable(test_example test_example.cpp)
target_link_libraries(test_example ${DYNAMIC_LIB1} ${DYNAMIC_LIB2} ${STATIC_LIB1})
Double check in Visual Studio that all libraries were added as linker inputs, as expected. If you still get linker errors, it means that something is wrong with your third-party .lib file. Open a new question with the exact linker error that you get.
Here is how we are doing it:
Firstly, use add_library with final arguments STATIC IMPORTED. Then subsequently use set_property to set the IMPORTED_LOCATION property, which is a path to the built library. For example, we pull in gtest like so:
add_library(gtest UNKNOWN IMPORTED)
set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${binary_dir}/googlemock/gtest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest.a)
Then, gtest is a known library in your build system and you can link with it normally later on by just doing
target_link_libraries(target-name gtest)
See also: Cmake imported libraries documenation

IMPORTED library that sets linker search directories only

The project I am working on has numerous external dependencies that I am now converting to proper IMPORTED targets with their IMPORTED_LOCATION or IMPORTED_IMPLIB set, along with their INTERFACE_INCLUDE_DIRECTORIES. This is much cleaner than just adding all directories to each target globally as it was before.
I'm running into a problem that there is now a library that defines the library that needs to be linked in the source file using a MSVC-specific #pragma. I tried adding an MODULE IMPORTED library, but that results in NAME-NOTFOUND.obj being linked, which is not what I want and not what the documentation seems to imply.
I also tried CMake 3.x's INTERFACE IMPORTED library type, which results in the #pragma-defined library being linked, but not found, because I found no way to specify the linker search directory for that target. I would prefer a solution that works for CMake 2.8.12.1.
Is there a way to solve this without naming the exact library file in the CMake script?