My structure is actually very simple but make produces the following linker error:
/ld.exe:
CMakeFiles\hello.dir/objects.a(hello.cpp.obj):hello.cpp:(.text+0x2b):
undefined reference to `Mathe::sum(int, int)'
My folder structure is:
+ CMakeLists.txt
+ src
-- hello.cpp
+ lib
-+ mathe
--- mathe.h
--- mathe.cpp
--- CMakeLists.txt
CMakeLists.txt in lib/mathe folder looks like this:
cmake_minimum_required(VERSION 3.2)
project(mathe LANGUAGES CXX)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
add_library(mathe SHARED)
target_sources(mathe PRIVATE mathe.cpp)
the one in the root dir:
cmake_minimum_required(VERSION 3.8)
project(hello LANGUAGES CXX)
add_subdirectory(lib/mathe)
set(SOURCE src/hello.cpp)
add_executable(hello ${SOURCE})
target_link_directories(hello PRIVATE mathe)
target_include_directories(hello PRIVATE lib/mathe)
the hello.cpp has the following content:
#include <iostream>
#include "mathe.h"
using namespace std;
int main()
{
Mathe m;
int r = m.sum(2,3);
return 0;
}
the lib looks like this:
mathe.h:
#ifndef MATHE_H
#define MATHE_H
class Mathe
{
public:
int sum(int, int);
};
#endif
mathe.cpp:
#include "mathe.h"
int Mathe::sum(int a, int b)
{
return a+b;
}
replacing target_link_directories with target_link_libraries solved it.
Related
To be summarized, I have an Object target (a_object) which is PUBLIC linked to a Shared Library (base). The Object target is compiled fine, however when I link that Object target to an executable (main), I got undefined symbol error from a function in base library when building that executable.
For more details:
Project tree
src
+---base
| CMakeLists.txt
| parser_helper.cpp
| parser_helper.hpp
|
\---module
a.cpp
a.hpp
CMakeLists.txt
main.cpp
Sources files:
base/parser_helper.hpp
#include <istream>
#include <string>
namespace base {
class line : public std::string {
public:
friend auto operator>>(std::istream& is, line& line) -> std::istream&;
};
} // namespace base
base/parser_helper.hpp
#include "base/parser_helper.hpp"
namespace {
using base::line;
} // namespace
auto base::operator>>(std::istream& is, line& line) -> std::istream& {
return std::getline(is, line);
}
base/CMakeLists.txt
add_library(base SHARED parser_helper.cpp parser_helper.hpp)
target_compile_options(base PRIVATE ...)
target_compile_features(base PRIVATE ...)
target_include_directories(base PRIVATE ...)
module/a.hpp
#include <istream>
namespace longlp {
void f(std::istream& input_stream);
...
} // namespace longlp
module/a.cpp
#include "module/a.hpp"
#include <algorithm>
#include <iterator>
#include "base/parser_helper.hpp"
namespace {
using base::line;
} // namespace
namespace longlp {
void f(std::istream& input_stream) {
std::for_each(std::istream_iterator<line>(input_stream),
std::istream_iterator<line>(),
[](const line& line) {
// ...
});
}
} // namespace longlp
module/main.cpp
#include <sstream>
#include "module/a.hpp"
int main() {
std::stringstream input("123\n123");
longlp::f(input);
return 0;
}
module/CMakeLists.txt
add_library(a_object OBJECT)
target_sources(a_object PRIVATE a.cpp a.hpp)
target_compile_options(a_object PRIVATE ...)
target_compile_features(a_object PRIVATE ...)
target_include_directories(a_object PRIVATE ...)
target_link_libraries(a_object PUBLIC base)
add_executable(main)
target_sources(main PRIVATE main.cpp)
target_compile_options(main PRIVATE ...)
target_compile_features(main PRIVATE ...)
target_include_directories(main PRIVATE ...)
target_link_libraries(main PRIVATE a_object)
Error log when building main
[build] lld-link: error: undefined symbol: class std::basic_istream<char, struct std::char_traits<char>> & __cdecl base::operator>>(class std::basic_istream<char, struct std::char_traits<char>> &, class base::line &)
[build] >>> referenced by C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\iterator:290
[build] >>> src/module/CMakeFiles/a_object.dir/a.cpp.obj:(private: void __cdecl std::istream_iterator<class base::line, char, struct std::char_traits<char>, __int64>::_Getval(void))
I got no error when building a_object individually. From Cmake documentation on linking Object target, I think it is enough to just linking the a_object to main, am I missing something?
Writing the files straight into the add_library instead of the target_sources might work.
Also, write a global CMakeLists.txt file and link everything there.
I'm working on an embedded Lua project and noticed that the behavior is different if I'm using a native Linux compiler vs the MinGw-w64 Cross Compiler. I'm using Swig to generate the wrapper files, and CMake to build the project (and testing with Wine).
node.h
#ifndef NODE_H
#define NODE_H
class Node {
public:
static Node* GetRoot();
int GetCount();
void SetCount(int count);
private:
static Node *root;
int count;
};
#endif /* NODE_H */
node.cpp
#include "node.h"
Node* Node::GetRoot() {
return root;
}
int Node::GetCount() {
return count;
}
void Node::SetCount(int count) {
this->count = count;
}
Node* Node::root = {new Node()};
node.i
%module node
%{
#include "node.h"
%}
%include "node.h"
main.cpp
#include <iostream>
#include "node.h"
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
extern "C" int luaopen_node(lua_State* L);
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaopen_node(L);
luaL_loadfile(L, "main.lua");
lua_call(L, 0, 0);
lua_getglobal(L, "init");
lua_call(L, 0, 0);
std::cout << Node::GetRoot()->GetCount() << std::endl;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(Singleton)
find_package(Lua REQUIRED)
add_executable(singleton main.cpp)
target_link_libraries(singleton nodelib)
target_link_libraries(singleton nodelua)
target_link_libraries(singleton ${LUA_LIBRARIES})
add_library(nodelib SHARED)
target_sources(nodelib PUBLIC
node.h
node.cpp)
find_package(SWIG REQUIRED)
include(UseSWIG)
set_property(SOURCE node.i PROPERTY CPLUSPLUS ON)
swig_add_library(nodelua
TYPE SHARED
LANGUAGE lua
SOURCES node.i)
target_include_directories(nodelua PRIVATE "${PROJECT_SOURCE_DIR}")
swig_link_libraries(nodelua
PRIVATE
nodelib
${LUA_LIBRARIES})
main.lua
function init()
local root = node.Node.GetRoot()
root:SetCount(1)
end
Could anyone explain why the output is 1 when compiled natively and 0 when cross compiled with MinGw? How can I get the singleton to properly update when returning from the embedded Lua call?
For posterity, the issue is that DLLs don't handle static members like this well. Since both the singleton executable and the nodelua library have a dependency on nodelib, they both get their own copy of the static member declared in its header files. Solve this by making root a static global in the node.cpp file.
(Also make nodelua a static library)
I have two source files, main.cc, foo.cc.
#include <iostream>
using namespace std;
int main() {
cout << "main\n";
}
foo.cc
#include <iostream>
using namespace std;
class foo {
public:
foo() {
cout << "foo ctor\n";
}
};
static foo foo_obj;
When I manually compile like this:
$ g++ -c foo.cc -o libfoo.a
$ g++ main.cc libfoo.a -o main
$ ./main
foo ctor
main
But when I use cmake, it won't print foo ctor. Here's the CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_FLAGS "-std=c++11")
add_library(foo STATIC foo.cc)
add_executable(main main.cc)
target_link_libraries(main foo)
Obviously cmake has done something that I don't expect.
It turns out that -Wl,--whole-archive can be used to avoid this. For example write this:
target_link_libraries(main
"-Wl,--whole-archive"
foo
"-Wl,--no-whole-archive"
)
I had a problem in the CMake that was fixed thanks to mascoj's help. Now I have this I run the test of the SocketTests file: "Empty tests suite"
If I order inside the class, the test works. Here is the architecture of the project:
+-- CMakeLists.txt
+-- Serveur
| +-- CMakeLists.txt
| +-- Serveur.cpp
| +-- Serveur.h
| +-- Socket.cpp
| +-- Socket.h
|
+-- Tests
| +-- CMakeLists.txt
| +-- main.cpp
| +-- lib
| +-- ServeurTests
| +-- SocketTests.cpp
The different files :
./ CMakeLists.txt :
cmake_minimum_required(VERSION 3.10)
project(ServeurCheckIn)
set(CMAKE_CXX_STANDARD 14)
add_subdirectory(Serveur)
add_subdirectory(Tests)
Serveur/CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(ServeurCheckIn)
set(CMAKE_CXX_STANDARD 14)
add_library(ServeurCheckIn SHARED Serveur.cpp Serveur.h Socket.cpp Socket.h)
Serveur/Socket.h :
#include <sys/socket.h>
#include <netinet/in.h>
namespace Serveur
{
class Socket
{
public:
Socket(int domaine, int type, int protocole);
int Domaine();
int Type();
int Protocole();
private:
int _domaine;
int _type;
int _protocole;
};
}
Serveur/Socket.cpp:
#include "Socket.h"
using namespace Serveur;
Socket::Socket(int domaine, int type, int protocole) :
_domaine(domaine), _type(type), _protocole(protocole)
{
}
int Socket::Domaine()
{
return _domaine;
}
int Socket::Type()
{
return _type;
}
int Socket::Protocole()
{
return _protocole;
}
Tests/CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(Tests)
set(CMAKE_CXX_STANDARD 14)
add_subdirectory(lib/googletest-master)
include_directories(lib/googletest-master/googletest/include)
include_directories(lib/googletest-master/googlemock/include)
add_executable(Tests main.cpp ServeurTests/SocketTests.cpp )
target_link_libraries(Tests gtest gtest_main ServeurCheckIn)
enable_testing()
Tests/SocketTests.cpp:
#include <gtest/gtest.h>
#include "../../Serveur/Serveur.h"
using namespace Serveur;
class SocketTests : public testing::Test
{
public:
SocketTests() : _socket(AF_INET, SOCK_RAW, IPPROTO_IP)
{
}
protected:
Socket _socket;
};
TEST_F(SocketTests, CreateSocket_SocketIsCreated)
{
ASSERT_EQ(1, 1);
}
Your Tests executable needs to be linked against your library you make with your other CMake.
target_link_libraries(Tests gtest gtest_main ServeurCheckIn)
Without it, the definitions for those functions will not be present at link time.
I use clion in osx to compile my c++ project using clang, but it complains about duplicate symbol for architecture x86_64, here is the detail message:
duplicate symbol __ZN4Util16axisAngle2rotMatERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEEf in:
CMakeFiles/ahrs.dir/src/algs.cpp.o
CMakeFiles/ahrs.dir/src/AHRS.cpp.o
ld: 1 duplicate symbol for architecture x86_64
I search for a while and it seems that I might link the header file in wrong way, but I look through my cpp and I think I didn't do something wrong.
algs.cpp:
#include <algs.h>
#include <Util.h>
#include <AHRS.h>
AHRS.cpp:
#include <AHRS.h>
#include <Util.h>
algs.h:
#ifndef AHRS_ALGS_H
#define AHRS_ALGS_H
#include <Dense>
using namespace Eigen;
class algs {
private:
VectorXi stationary;
public:
VectorXd filter(MatrixX3d& acc);
void gradient_descent(MatrixX3d acc, MatrixX3d gyo, VectorXi time);
};
#endif //AHRS_ALGS_H
Util.h:
#ifndef AHRS_UTIL_H
#define AHRS_UTIL_H
#include <math.h>
#include <Dense>
#include <src/Geometry/Quaternion.h>
#include <vector>
using namespace Eigen;
namespace Util {
//many inline functions in this namespace.
...
}
#endif //AHRS_UTIL_H
AHRS.h:
#ifndef AHRS_AHRS_H
#define AHRS_AHRS_H
#include <Dense>
using namespace Eigen;
class AHRS {
private:
Quaterniond q;
Vector3d int_error;
int kp_ramped;
public:
double kp;
int ki;
int kp_init;
int init_period;
double sample_period;
Quaterniond quaternion;
AHRS();
void reset();
};
#endif //AHRS_AHRS_H
and the CMakeLists.txt:
cmake_minimum_required(VERSION 3.6)
project(AHRS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_subdirectory(test)
include_directories(Eigen)
include_directories(include)
set(AHRS_HEAD include/)
set(AHRS_SRC src/main.cpp src/Biquad.cpp src/filtfilt.cpp src/Butterworth.cpp src/algs.cpp src/AHRS.cpp)
add_executable(ahrs ${AHRS_SRC} ${AHRS_HEAD})
all my header files is in the include folder. How can I fix this issue?