Problems when linking my main output library with my test executable - c++

I'm building a "framework" library which one I'm trying to integrate Google Tests. It's a pretty small library, that at the end gives me a .so or .dll file.
When I was starting to tests my library, I found a configuration (details below) that works fine on my CMakeFile at my linux environment. But when I try to run the same project using a MSBuild for MSVC14, it gives me a link error
LINK : fatal error LNK1104: cannot open file '..\src\Debug\foobar.lib'
I'm thinking that my cmake is guessing the lib name wrong (foobar.lib instead of foobar.dll), but I couldn't find why nor how to fix it.
Also, I don't know if this is really the best way for me testing this. What I want is a way to test the whole framework (initializing, creating stuffs, checking returns etc..) without a main.cpp file, and meanwhile start to create the unit tests.
So, my question is.. What am I doing wrong that at the Windows environment the linker does not find the foobar lib built by src/CMakeLists.txt? (I checked, and the lib is created in "src/Debug/foobar.dll", same dir that appears at the error, and works fine)
Also, is my method so wrong that windows just don't wanna deal with? lol I mean, it's wrong to do something like I'm trying to do? It's not that I do not want to make unit tests, which I'll be doing soon, but I really like to build and try my lib without using any external exec binary before I starting to do that.
Thanks!
OBS:
My google tests is working fine both in linux and windows;
I can run the test FooA if I remove the FooBar test, which is linking to foobar lib.
Using my linux environment this configuration works perfectly.
Update:
As #vre suggested, I found the macro __declspec(dllexport) and put it before my FooBar class name and the compilation passed, but it crashes when I run and throws this warning when compiling:
warning C4251: 'FooBar::_impl': class 'std::unique_ptr<FooBar::FooBarImpl,
std::default_delete<_Ty>>' needs to have dll-interface to be used by clients of class 'FooBar'
That's because I have a PImp implementation of the FooBar class. So, I have this:
class __declspec(dllexport) FooBar
{
...
private:
class FooBarImpl;
std::unique_ptr<FooBarImpl> _impl;
}
I don't really know what it means yet. Trying to find out why it crashes.
My project has this file tree:
├── CMakeLists.txt
├── include
| ├── FooBar.hpp
├── src
│   ├── CMakeLists.txt
│   ├── FooBar.cpp
│   ├── FooA
│   │   └── CMakeLists.txt
│   ├── FooB
│   │   └── CMakeLists.txt
│   └── FooC
│   └── CMakeLists.txt
└── test
├── CMakeLists.txt
├── FooBar
│   └── FooBarTest.hpp
├── FooA
│   ├── FakeBar.hpp
│   ├── FooATest.hpp
│   └── mockObj.hpp
My main CMakeLists.txt is like this:
...
set(FOOBAR_INCLUDE "${PROJECT_SOURCE_DIR}/include/FooBar.hpp")
# Include src main CMakeLists
add_subdirectory("${PROJECT_SOURCE_DIR}/src")
# Include tests if enabled
if (test)
add_subdirectory("${PROJECT_SOURCE_DIR}/test")
endif ()
My src/CMakeLists.txt:
...
set(FOOBAR_SOURCES "FooBar.cpp")
# Build
add_library(foobar SHARED ${FOOBAR_SOURCES} ${FOOBAR_INCLUDE})
# Links the library with components.
target_link_libraries(foobar FooA FooB FooC)
And my test/CMakeLists.txt is something like this:
enable_testing()
# Include directories used for testing.
include_directories("${CMAKE_SOURCE_DIR}/src"
"${CMAKE_SOURCE_DIR}/include"
"FooA/"
"FooBar/")
# Include the files for testing.
set(INCLUDE_TESTS "${CMAKE_SOURCE_DIR}/src/FooA/FooA.cpp"
"${CMAKE_SOURCE_DIR}/src/FooA/Bar.cpp")
# Include the test source files.
set(TEST_SOURCES "main.cpp"
"FooBar/JepluTest.hpp"
"FooA/FakeBar.hpp"
"FooA/FooATest.hpp")
# Build
add_executable(foobar-test ${TEST_SOURCES} ${INCLUDE_TESTS})
# Links the library with components. (HERE IS WHERE OCCURS THE PROBLEM)
target_link_libraries(foobar-test gtest foobar)
# Not really important right now
add_test(NAME foobar-test COMMAND foobar-test)

Reformulating and enhancing my previous comments:
You need to export symbols from the DLL on Windows otherwise no import library is created, and that's what MSBuild is complaining about.
First you should add to your FooBar.hpp header the following construct:
#ifdef WIN32
#ifdef FOOBARLIB_EXPORTS
#define FOOBARLIB_API __declspec(dllexport)
#else
#define FOOBARLIB_API __declspec(dllimport)
#endif
#else
#define FOOBARLIB_API
#endif
Later mark your classes, functions and symbols to be exported as follows:
void FOOBARLIB_API foobar(char*)
{
}
In your CMakeLists.txt after creating the shared library target foobar add the line:
target_compile_definitions(foobar PRIVATE FOOBARLIB_EXPORTS)
EDIT:
As #vre commented, these CMake properties are also needed because Windows does not load a DLL located in another folder, causing a crash when it tries to run the executable. So, when a DLL is build and the CMAKE_RUNTIME_OUTPUT_DIRECTORY variable is set, the output library goes to the same directory as the test .exe file.
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

Related

How cmake add_subdirectory works for projects dependency?

I had some problems about cmake build system:
There are may projects in my code like this:
├── CMakeLists.txt
├── project1
│   └── CMakeLists.txt
└── project2
└── CMakeLists.txt
...
I want to use add_subdirectory to build all projects,so I write them in top level CMakeLists.txt
add_subdirectory(project1)
add_subdirectory(project2)
And there are dependencies between projects ,for example project1 need find project2:
# project1/CMakeLists.txt
find_package(project2 REQUIRED)
And I will get an error message,because project1 can't find project2.
By not providing "Findproject2.cmake" in CMAKE_MODULE_PATH this
project has asked CMake to find a package configuration file provided by
"project2", but CMake did not find one.
All I know is that order won't solve the problem.
So I want to konw how deal with this problem?Any suggestions?

How can I avoid relative paths in #includes when building with Bazel

I'm struggling to understand the logic of how includes work in Bazel targets. I want my code to be modular, so I am trying to avoid #include statements with relative or long absolute paths.
Suppose I have the following workspace structure:
tree .
.
├── BUILD
├── is_binary_tree
│   ├── BUILD
│   └── is_binary_tree.cpp
├── lib
│   ├── BUILD
│   ├── graphs.cpp
│   └── graphs.h
└── WORKSPACE
I'm getting the following warning when trying to bazel build //is_binary_tree:is_binary_tree and I don't understand what it means :
WARNING: /is_binary_tree/BUILD:1:10:
in includes attribute of cc_binary rule
//is_binary_tree:is_binary_tree: '../lib' resolves to 'lib' not below
the relative path of its package 'is_binary_tree'. This will be an
error in the future
Why would ../lib resolve to lib. Lib should be in the parent directory of is_binary_tree, so from the standpoint of is_binary_tree it can be found at ../lib, isn't this right?
To get rid of the relative path and avoid having something like #include ../lib/graphs.h in is_binary_tree/is_binary_tree.cpp I added an includes attribute to my is_binary_tree target like so:
is_binary_tree/is_binary_tree.cpp
#include "graphs.h"
int main(){
return 0;
}
is_binary_tree/BUILD
cc_binary(
name="is_binary_tree",
srcs=["is_binary_tree.cpp"],
includes=["../lib"],
deps=["//lib:graphs"],
)
And I'm getting the aforementioned WARNING. What am I missing?
And more broadly, what is the best way to include dependencies without having long relative paths in #include statements ? (I want my code to be modular and not specific to a given Bazel workspace folder organization)
Thanks
That includes should go in //lib:graphs, so that anything which depends on it (has it in deps) uses it. lib/BUILD should look like this:
cc_library(
name = "graphs",
hdrs = ["graphs.h"],
srcs = ["graphs.cpp"],
includes = ["."],
visibility = ["//visibility:public"],
)
Then you drop includes from is_binary_tree and it should work.
In general, each Bazel target contains information about its files. It depends on other targets to use their files.
More broadly, Bazel defaults to #include paths relative to the base of the repository. That means you'd write #include "lib/graphs.h" in any file, whether that's is_binary_tree/is_binary_tree.cpp or x/y/z/foobar.cpp. That avoids collisions between graphics/constants.h and audio/constants.h, without using absolute paths.

How to link an external library with CMake project

I made a Non-Qt project, Plain C++ Application in QT creator. My current folder structure is like this:
.
├── client
│   ├── client.cpp
│   └── client.h
├── CMakeLists.txt
├── CMakeLists.txt.user
├── main.cpp
└── server
├── server.cpp
└── server.h
My CMakeLists.txt file looks like this:
cmake_minimum_required(VERSION 3.5)
project(eshraagh-project LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(eshraagh-project main.cpp server/server.h server/server.cpp client/client.h client/client.cpp)
In my main file, I included server.h and client.h and made instances of both of them, and it didn't give any errors.
The problem arises when I try to use an external library (this library). I have no idea how to use it.
I tried to copy contents of its src folder (cpnet-export.h, cpnet-network.h and cpnet-network.c) into my project and add them to CMakeLists, just like I did with server and client files, but it doesn't work. I copied the server part of the repository and pasted it in my main, but it gives me errors such as undefined reference to 'cpnet_bind' and more (A little note: The repository uses the functions with net prefix, but QT recommender told me to write cpnet prefix instead. I don't know why this is happening).
Linking a library of an executable in CMake is achieved by using the target_link_libraries function. In your case,
target_link_libraries(eshraagh-project PRIVATE cpnet)
Here, cpnet could be the name of a target that you CMake project knows (otherwise, it is turned into some kind of platform specific -lcpnet linker flag). In order to make CMake know about the cpnet library, you can
add the external library sources to your project (as a git submodule, or by tracking them yourself), for this example let's say they the sources are located at lib/cpnet
tell CMake to include the configuration instructions from that folder. This works if the external project uses CMake, too, and doesn't mess with global variables and settings (this seems to be the case here).
So in your toplevel CMakeLists.txt:
add_subdirectory(lib/cpnet)
Note that this must be done before the target_link_libraries call.

Reason to add empty source file to a STATIC library?

I've seen this quite a lot in C++, that developers add an empty source file to the library in CMake. One example is here, with the empty source file found here.
The CMake file has this line:
# build the library
add_library(${PROJECT_NAME} STATIC src/dependency-tracker.cc)
This is only the case if there are no other source files in the src folder, so the library would be 'header only'. Why do they do this?
The directory structure i was referring to:
.
├── CMakeLists.txt
├── include
│   └── okvis
│   └── kinematics
│   ├── implementation
│   │   └── Transformation.hpp <- header only implementation
│   ├── operators.hpp
│   └── Transformation.hpp
├── src
│   └── dependency-tracker.cc <- empty source file
└── test
├── runTests.cpp
└── TestTransformation.cpp
The project specifies CMake 2.8.11 as a minimal requirement:
cmake_minimum_required(VERSION 2.8.11)
This version lacks for INTERFACE library type, which nowadays is a standard representation of a header-only library. (Support for INTERFACE libraries firstly appeared in CMake 3.0).
Without INTERFACE library available, a normal library with a single empty source file looks like a good alternative.
I don't know why dependency-tracker.cc name choosen for the empty source file. Probably, this name has some special meaning for the project's developers.

CMake: Linking a third-party library to a project library

I am currently working on a C++ project using CMake as its build system.
The projects consists of several output executables, each having relatively little custom code, but leveraging a few common libraries:
programX
|
├── CMakeLists.txt (this contains the main executable targets)
|
├── Engine
│   ├── ...
│   ├── CMakeLists.txt
|
├── Utils
│   ├── third_party (this is what I added)
│   │   └── backward-cpp
│   | └ CMakeLists.txt
│   ├── ...
│   └── CMakeLists.txt
|
└── etc.
The main functionality of the project is contained inside an Engine library which is statically linked to the main executables using something like target_link_libraries(programX Engine). Many utilities are also contained in a separate Utils library.
I have added a CMake dependency to one of these project libraries (it's the backward-cpp stacktrace prettifier). That project is also built using CMake.
In the interest of modularity, I have added the backward-cpp project as a dependency to the only project library which actually uses it, Utils. I did this in order not to "pollute" the main CMakeLists.txt file with directives only pertaining to a small part of the project.
My Utils/CMakeLists.txt therefore looks like this:
SET(UTILS_HEADERS ...)
set(UTILS_OBJECTS Dummy.cpp ${UTILS_HEADERS})
# This is the new dependency!
add_subdirectory(third_party/backward-cpp)
SOURCE_GROUP("" FILES ${UTILS_HEADERS})
# 'BACKWARD_ENABLE' and 'add_backward' are needed for linking.
add_library(Utils ${UTILS_OBJECTS} ${BACKWARD_ENABLE})
add_backward(Utils)
Doing this, however, does not work, and the project ends up not linking (the symbols from the backward-cpp library are not found), unless I link the output executables to the third party library directly, in the root CMakeLists.txt file (add_backward(MainExecutableA-Z)).
I am aware that one cannot link static libraries to other static libraries, but I would be interested in knowing if there is a nice way to achieve this modularization of static libraries and their dependencies using CMake.
(Alternatively, I could always just link everything directly to the main targets, since that always works.)
Update (May 22nd 2017)
I've managed to get everything working now, with backwards-cpp being controlled 100% from the "narrowest" CMakeLists.txt file, thanks to the helpful answers I got. Here's the Utils/CMakeLists.txt file I ended up with (non-relevant parts removed):
SET(UTILS_HEADERS ...)
SET(UTILS_SOURCES ...)
# If enabled, enables sensible stack traces on Linux, complete with corresponding source
# code, where available. CUDA errors also produce complete stack traces when this is on.
# If disabled, the error messages degrade gracefully to file/line information.
OPTION(WITH_BACKWARDS_CPP "Build with backwards-cpp stack trace dumping library? (Linux-only)" TRUE)
message(STATUS "backwards-cpp-enhanced stack traces? " ${WITH_BACKWARDS_CPP})
if(WITH_BACKWARDS_CPP)
# Support 'backward-cpp,' a lean stacktrace printing library for Linux.
add_definitions(-DWITH_BACKWARDS_CPP)
add_subdirectory(third_party/backward-cpp)
endif()
SOURCE_GROUP("" FILES ${UTILS_HEADERS} ${UTILS_SOURCES})
add_library(Utils ${UTILS_HEADERS} ${UTILS_SOURCES})
# ...unrelated CUDA stuff...
if(WITH_BACKWARDS_CPP)
# Link agains libbfd to ensure backward-cpp can extract additional information from the binary,
# such as source code mappings. The '-lbfd' dependency is optional, and if it is disabled, the
# stack traces will still work, but won't show unmangled symbol names or source code snippets.
# You may need to set BACKWARD_USE_BFD to 0 in its `hpp` and `cpp` files to avoid linker errors.
target_link_libraries(Utils PUBLIC -lbfd)
target_link_libraries(Utils PUBLIC backward)
endif()
After looking inside the BackwardConfig.cmake and reading the project's README I came to the conclusion that the most easy way to link your executable with the Backward-cpp is using the add_backward(target) macro as you mentioned in your question.
The other option described under Modifying CMAKE_MODULE_PATH subtitle in the README shuld work as well but I not tested. The find_package in Config mode will search for file called <name>Config.cmake which is BackwardConfig.cmake in this case, so you don't have to write any extra CMake modules like FindBackward.cmake. As a try I would do the following:
set(UTILS_HEADERS ...)
set(UTILS_OBJECTS Dummy.cpp ${UTILS_HEADERS})
source_group("" FILES ${UTILS_HEADERS})
add_library(Utils ${UTILS_OBJECTS})
list(APPEND CMAKE_MODULE_PATH /path/to/backward-cpp)
find_package(Backward)
target_link_libraries(Utils PUBLIC Backward::Backward)
After reading the README of backward-cpp, I would try the following (only the last two lines change):
SET(UTILS_HEADERS ...)
set(UTILS_OBJECTS Dummy.cpp ${UTILS_HEADERS})
# This is the new dependency!
add_subdirectory(third_party/backward-cpp)
SOURCE_GROUP("" FILES ${UTILS_HEADERS})
add_library(Utils ${UTILS_OBJECTS})
target_link_libraries(Utils PUBLIC backward)
Note that PUBLIC in the last statement takes care of setting the include directories and link libraries when you link other targets against Utils.