I'm not very familiar with both cmake and mingw.
I have some source code that can be build with it (and the build process works fine with mingw32-make). The problem is, I would like to output the DLLs and not the .exe files.
I have some CMakeList file that I believe stores the configuration I have to change (that part should be responsible to produce the .exe files for .cpp files in Examples/ directory, taking some dependencies into account):
# C examples
if(PSMOVE_BUILD_EXAMPLES)
foreach(EXAMPLE example multiple dump_calibration battery_check)
add_executable(${EXAMPLE} examples/c/${EXAMPLE}.c)
target_link_libraries(${EXAMPLE} psmoveapi)
endforeach()
if(PSMOVE_BUILD_TRACKER AND PSMOVE_BUILD_TUIO_SERVER)
include_directories(${PSMOVEAPI_SOURCE_DIR}/external/TUIO_CPP/TUIO)
include_directories(${PSMOVEAPI_SOURCE_DIR}/external/TUIO_CPP/oscpack)
add_executable(tuio_server examples/c/tuio_server.cpp
external/TUIO_CPP/TUIO/TuioClient.cpp
...
external/TUIO_CPP/oscpack/ip/win32/NetworkingUtils.cpp
external/TUIO_CPP/oscpack/ip/win32/UdpSocket.cpp)
set_target_properties(tuio_server PROPERTIES
COMPILE_FLAGS -DOSC_HOST_LITTLE_ENDIAN)
target_link_libraries(tuio_server psmoveapi psmoveapi_tracker)
else()
# Disable the TUIO Server if we don't build the tracker
set(PSMOVE_BUILD_TUIO_SERVER OFF)
endif()
if(PSMOVE_BUILD_TRACKER)
foreach(EXAMPLE distance_calibration)
add_executable(${EXAMPLE} examples/c/${EXAMPLE}.c)
target_link_libraries(${EXAMPLE} psmoveapi psmoveapi_tracker)
endforeach()
endif()
endif()
I guess I should add -DBUILDING_EXAMPLE_DLL and -shared options somewhere. But where exactly? Or maybe I'm missing the point?
To make a dll you need add_library(mydlltarget SHARED mysourcefiles) instead of add_executable(myexetarget mysourcefiles)
Also to make a dll from code that was an executable you will at minimum have to modify your headers to export the classes/functions that you want exported. From the documentation for building a dll with mingw it appears that the process is similar to Visual Studio. Where you have a header define a macro that translates to __declspec(dllexport) when building the dll and __declspec(dllimport) when using the dll.
A sample of the export header looks like this:
#ifdef BUILDING_EXAMPLE_DLL
#define EXAMPLE_DLL __declspec(dllexport)
#else
#define EXAMPLE_DLL __declspec(dllimport)
#endif
Then the modification for your class is like this:
class EXAMPLE_DLL MyClass
{
public:
MyClass() {};
virtual ~MyClass() {};
void func(void);
};
Then you need to define BUILDING_EXAMPLE_DLL when building the dll. You can do that in CMake with an add_definitions(-DBUILDING_EXAMPLE_DLL)
Also CMake provides support for generating the export header with GENERATE_EXPORT_HEADER
Doc for GenerateExportHeader
Related
So I have a project (meant to be supported on MacOS, Linux, and Windows) where I am building a shared library and a set of executables linked to that library. In my root CMakeLists.txt I have added:
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
So that all symbols are hidden by default regardless of on Windows (which does this by default) or Linux. This will require me to manually export symbols of the public API. To help facilitate this, I've written a defines.hpp header in my project's utils/ directory which contains the following:
#ifndef __DEFINES_H_
#define __DEFINES_H_
#if defined(linux) || defined(__linux__)
#define EXPORT __attribute__((visibility("default")))
#elif defined(_WIN64) || defined(__WIN32__)
#if defined(COMPILE_LIB)
#define EXPORT __declspec(dllexport)
#elif
#define EXPORT __declspec(dllimport)
#endif
#endif
#endif
The idea being then I would include this header into any header that contains declarations that need to be exported (and subsequently imported as well) via:
#include "utils/defines.hpp"
class EXPORT MyCoolClass();
EXPORT void MyCoolFunction();
(I have not tested this yet so if there are any glaring issues with what I've written please let me know!)
My question is, it is not entirely clear to me how to define the COMPILE_LIB macro, given that the library and exectuables are built/linked with the same CMake setup. How can I ensure that the library is built using dllexport and then linked to the executables using dllimport within the same CMake build? Or would I need to take a different approach?
The accepted answer in this previous SO post seems to indicate using a compiler argument and building each separately, which isn't exactly what I am looking for. A separate answer indicates you should use the CMake defined projectname as when compiling the DLL it will define the macro projectname_EXPORTS. I'm also not sure that this will work again my shared library and the executables are all built within the same CMake project. (Relevant CMakeLists.txt files):
CMakeLists.txt for executables:
add_executable(quick-render quick_render.cpp)
target_link_libraries(quick-render ${PROJECT_NAME})
INSTALL(TARGETS quick-render DESTINATION bin)
...
CMakeLists.txt for library:
...
add_library(${PROJECT_NAME} SHARED
...
)
target_link_libraries(${PROJECT_NAME} PUBLIC
...
)
...
Would this approach still work here, or is it my CMake setup bad for using the project in multiple ways like this?
As Tsyvarev said in the comments,
Define the macro by using target_compile_definitions command with PRIVATE keyword. That way, the macro will be defined only when the library itself is compiled.
Adding to what Tsyvarev said, if you just use the GenerateExportHeader module, that part will be done for you automatically. It will also take care of generating C++ attributes for the compiler you configured the buildsystem to use.
When target_link_library(foo bar) is called with bar as a target of a SHARED library, CMake will use a static lib libbar.dll.a or bar.lib as an input on Windows. However, MinGW, for example, is capable of linking to a binary file like on Ubuntu. Is it possible to tell cmake to use a dll directly when target_link_library is called?
The obvious workaround is to use generator expressions:
target_link_libraries(foo PRIVATE $<TARGET_FILE:bar>)
Clearly, it has its shortcomings. When you link against a target, you also add its PUBLIC and INTERFACE included directories and linked libraries.
So, in order to fully link in that manner one would have to write something like:
get_target_property(INCLUDE_DIRS bar INTERFACE_INCLUDE_DIRECTORIES)
get_target_property(LINK_LIBS bar INTERFACE_LINK_LIBRARIES)
target_include_directories(foo PRIVATE ${INCLUDE_DIRS})
target_link_libraries(foo PRIVATE ${LINK_LIBS} $<TARGET_FILE:bar>)
So the question is about the possibility to override CMake's default target_link_libraries behavior.
Windows shared object creation works quite differently to on Linux. On Linux, all symbols (functions, classes, etc) are visible to consumers of a shared library by default. On Windows, the opposite is true - nothing is visible by default. This feeds in to shared library creation, because Visual C++ will generate two files per shared library - a .dll and a .lib file. The consumer still links against the lib - not directly against the dll. If you're not explicitly exporting any symbols in your source code, then linking will fail, because no .lib file is generated.
In order to do this, you should basically (on a per-library basis) create a file called "library_api.h" which contains the following:
#ifndef LIBRARY_API_H
#define LIBRARY_API_H
#if defined(WIN32)
#if defined(MYAPI)
#define LIBRARY_API __declspec(dllexport)
#else
#define LIBRARY_API __declspec(dllimport)
#endif
#else
#define LIBRARY_API
#endif
#endif
Then, include that in your header files in which your functions are defined for that library, and prefix them like:
#included "library_api.h"
LIBRARY_API int myfunction();
and in the source file where the definition is, do the same.
Then in CMake, you need to add where the library is made:
add_library(library SHARED source.cpp)
target_compile_definitons(library PUBLIC LIBRARY_API)
Now, the lib file should be generated, and CMake will be able to find it, and hence everything should work.
Note that you can do something similar to the Windows default behaviour on Linux to also hide symbol visibility. You can pass the flag -fvisibility=hidden to GCC, and modify the header slightly using __attribute__ ((visibility ("default"))), and then the behaviour is the same as on Windows. That can be quite useful if your primary development environment is on Linux but you need to build on Windows, because you get the same sort of behaviour and so don't end up with something that works on it but not cross-platform.
I am on Windows 10, Visual Studio 2015. Suppose I am building library A with CMakeLists looking like
cmake_minimum_required(VERSION 3.7)
project(A)
set(DLLIMPORT "__declspec(dllimport)")
set(DLLEXPORT "__declspec(dllexport)")
set(PROJECT_SRCS
${PROJECT_SOURCE_DIR}/src/TestA.cpp)
set(PROJECT_INCS
${PROJECT_SOURCE_DIR}/include/TestA.h)
add_library(${PROJECT_NAME} SHARED ${PROJECT_SRCS} ${PROJECT_INCS})
target_compile_definitions(${PROJECT_NAME} INTERFACE
WINDOWS_DLL_API=${DLLIMPORT})
target_compile_definitions(${PROJECT_NAME} PRIVATE
WINDOWS_DLL_API=${DLLEXPORT})
target_include_directories(${PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)
I am defining the macro WINDOWS_DLL_API as dllexport when it's building library A, and defining WINDOWS_DLL_API as dllimport for external applications that is linking library A. The problem is when I have another library B that is also linking A, I don't know how to overwrite WINDOWS_DLL_API back to dllexport. Below is my attempt of my CMakeLists for library B,
cmake_minimum_required(VERSION 3.7)
project(B)
set(DLLEXPORT "__declspec(dllexport)")
set(PROJECT_SRCS
${PROJECT_SOURCE_DIR}/src/TestB.cpp)
set(PROJECT_INCS
${PROJECT_SOURCE_DIR}/include/TestB.h)
add_library(${PROJECT_NAME} SHARED ${PROJECT_SRCS} ${PROJECT_INCS})
target_include_directories(${PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)
target_link_libraries(${PROJECT_NAME} A)
# does not work
target_compile_definitions(${PROJECT_NAME} PRIVATE
WINDOWS_DLL_API=${DLLEXPORT})
What is the right way to do it?
Concept of INTERFACE option for command target_compile_definitions (and for other target_* CMake commands) is to enforce something for all users of the library, both executables and libraries.
Intention to clear enforcement for at least single library's user means that the conception is used in a wrong way. And other approaches should be used instead.
In given case, you need to use different macro names for libraries A and B. And it is better to remove INTERFACE option completely, so even non-CMake users of your library will be happy.
TestA.h:
#ifdef BUILD_A
#define WINDOWS_DLL_API_A __declspec(dllexport)
#else
#define WINDOWS_DLL_API_A __declspec(dllimport)
#endif
...
WINDOWS_DLL_API_A void foo(void);
...
TestB.h:
#ifdef BUILD_B
#define WINDOWS_DLL_API_B __declspec(dllexport)
#else
#define WINDOWS_DLL_API_B __declspec(dllimport)
#endif
// Assume usage of A is here.
#include <TestA.h>
...
WINDOWS_DLL_API_B void bar(void);
A/CMakeLists.txt:
cmake_minimum_required(VERSION 3.7)
project(A)
...
add_library(${PROJECT_NAME} SHARED ...)
target_compile_definitions(${PROJECT_NAME} PRIVATE "BUILD_${PROJECT_NAME}=1")
B/CMakeLists.txt:
cmake_minimum_required(VERSION 3.7)
project(B)
...
add_library(${PROJECT_NAME} SHARED ...)
target_compile_definitions(${PROJECT_NAME} PRIVATE "BUILD_${PROJECT_NAME}=1")
target_link_libraries(${PROJECT_NAME} A)
See also this answer, which provides more detailed header, which works on Windows platforms too.
Note, that when the library B includes header from A, it treats foo() as imported, and this is correct: the function is defined in A, not in B. With your approach (even if you would manage to redefine WINDOWS_DLL_API for B), library B would incorrectly treat foo() as exported.
This is an advantage of the conception: intention to overcome a conception signals that you do something wrong.
Just wanted to add my piece of code I'm using (compatible with CMake versions prior to 2.8.12).
In my root CMakeLists.txt file I have:
if (MSVC)
add_definitions(-DWINDOWS_DLL_API=__declspec\(dllexport\))
else()
add_definitions(-DWINDOWS_DLL_API=)
endif()
In the (sub-)project's CMakeLists.txt using the DLL I've put:
if (MSVC)
remove_definitions(-DWINDOWS_DLL_API=__declspec\(dllexport\))
add_definitions(-DWINDOWS_DLL_API=__declspec\(dllimport\))
endif()
The MSVC checks are necessary in my case because I also cross-compile.
Reference
CMake - override compile flags for single files
Our Library uses Cmake while the Overall system uses Make file for build.
I want to port the value of a variable (preprocessor macro) defined in the makefile to Cmakefile and use it as preprocessor marco in source codes of my library.
How to do that?
You can define variable at CMake invocation like so:
cmake -DMY_VAR=ON <path_to_CMakeLists.txt>
Then later in your CMake file:
if (MY_VAR)
add_definitions(-DENABLE_MY_VAR)
endif()
And finally in your code:
#ifdef ENABLE_MY_VAR
// Your code
#endif
I wasn't sure what to search for for this one. So excuse me if this is simple. But let me outline the scenario and see what answers are out there.
Let's say I have a library which defines a structure like this:
struct Example {
int a;
#if B_ENABLED
int b;
#endif
};
This header gets installed as a part of the library's installation as a whole. My question here is that if my library defines B_ENABLED it will have a structure with these two variables included. However if my application does not define this as well. Then it will interpret the header as defining a struct with only one member.
Is the best way to handle this just to generate some kind of "options" header which would include all of the #defines that were specified in the library build?
My library builds with CMAKE. So a CMAKE solution for this is extra credit =D.
Solution #1 (configure + install)
Include config.hpp file in your header file(i.e. foo.hpp):
#ifndef FOO_HPP_
#define FOO_HPP_
#include "config.hpp" // FOO_DEBUG
class Foo {
public:
int result() const;
private:
int a_;
#ifdef FOO_DEBUG
int b_;
#endif // FOO_DEBUG
};
#endif // FOO_HPP_
config.hpp is output of configure_file command:
configure_file(config.hpp.in "${PROJECT_BINARY_DIR}/config/config.hpp")
include_directories("${PROJECT_BINARY_DIR}/config")
install(FILES Foo.hpp "${PROJECT_BINARY_DIR}/config/config.hpp" DESTINATION include)
input file config.hpp.in use special cmakedefine directive:
#ifndef CONFIG_HPP_
#define CONFIG_HPP_
#cmakedefine FOO_DEBUG
#endif // CONFIG_HPP_
Note that when you use installed library in other project:
you still need to specify include directories for library
if your library have dependencies you need to link them manually
you can't have 2 config files (Debug/Release)
Solution #2 (export/import target, recommended)
install(EXPORT ...) command can hold all information about using library
(aka usage requirements: including definitions, linked library, configuration etc):
add_library(Foo Foo.cpp Foo.hpp)
# Target which used Foo will be compiled with this definitions
target_compile_definitions(Foo PUBLIC $<$<CONFIG:Release>:FOO_DEBUG=0>)
target_compile_definitions(Foo PUBLIC $<$<CONFIG:Debug>:FOO_DEBUG=1>)
# This directory will be used as include
target_include_directories(Foo INTERFACE "${CMAKE_INSTALL_PREFIX}/include")
# This library will be linked
target_link_libraries(Foo PUBLIC pthread)
# Regular install
install(FILES Foo.hpp DESTINATION include)
# Install with export set
install(TARGETS Foo DESTINATION lib EXPORT FooTargets)
install(EXPORT FooTargets DESTINATION lib/cmake/Foo)
Installing such project will produce files (CMAKE_DEBUG_POSTFIX is d):
include/Foo.hpp
lib/libFoo.a
lib/libFood.a
lib/cmake/Foo/FooTargets-debug.cmake
lib/cmake/Foo/FooTargets-release.cmake
lib/cmake/Foo/FooTargets.cmake
Include FooTargets.cmake file to import installed library to project. For example using find_package command (need config, see configure_package_config_file):
add_executable(prog main.cpp)
find_package(Foo REQUIRED) # import Foo
target_link_libraries(prog Foo)
Note that:
path to include/Foo.hpp automatically added to compiler options
dependend library pthread is automatically added to prog linker option
definition FOO_DEBUG=0 added to Release build type
definition FOO_DEBUG=1 added to Debug build type
Rationale
So excuse me if this is simple
It is not (:
The root of the problem is ODR (C++ Standard 2011, 3.2 [basic.def.ord], p.3):
Every program shall contain exactly one definition of every non-inline function
or variable that is odr-used in that program; no diagnostic required. The
definition can appear explicitly in the program, it can be found in the
standard or a user-defined library
IMHO good general solution still not exists. Using CMake with imported configuration
can partially helps a little bit, but in some cases you still will get linker errors
(for example if you use library compiled with gcc, which linked to libstdcxx by default,
and try to link it to project with clang compiler, which linked to libcxx).
Some of this problems (not all, still) can be solved using toolchain files.
See examples.
Related
CMake tutorial
Exporting/importing targets
Modern CMake with Qt and Boost