Undefined reference after using CMAKE to generate a makefile - c++

I can generate my CMake project, but I can't build it.
I have a fairly straightforward project structure:
├── bin
├── build
├── CMakeLists.txt
├── include
│   └── project
│   ├── base_socket.h
│   ├── tcp_client.h
│   ├── tcp_server.h
│   ├── udp_client.h
│   └── udp_server.h
├── LICENSE.txt
├── README.md
└── src
└── project
├── base_socket.cpp
├── CMakeLists.txt
├── main.cpp
├── tcp_client.cpp
├── tcp_server.cpp
├── udp_client.cpp
└── udp_server.cpp
And a fairly straight forward CMakeLists.txt file in the top directory:
# Project initialization
cmake_minimum_required(VERSION 2.7.2 FATAL_ERROR)
project("cpp_sockets")
# Add include directory
include_directories(include)
# Add subdirectories
add_subdirectory(src/project)
And also a fairly simple one in src/project/CmakeLists.txt:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
set(HEADER_DIR ${CMAKE_SOURCE_DIR}/include/project)
set(HEADER_FILES
${HEADER_DIR}/base_socket.h
${HEADER_DIR}/tcp_client.h
${HEADER_DIR}/tcp_server.h
${HEADER_DIR}/udp_client.h
${HEADER_DIR}/udp_server.h
)
add_executable(cpp_sockets main.cpp ${HEADER_FILES})
When I cd into /build and type cmake .. it works fine.
However, when I follow that with make, I get many terrible errors about undefined reference.
main.cpp:(.text+0x2c6): undefined reference to `UDPClient::UDPClient(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x2eb): undefined reference to `UDPClient::send_message(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x359): undefined reference to `UDPServer::UDPServer(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x380): undefined reference to `UDPServer::socket_bind()'
main.cpp:(.text+0x38c): undefined reference to `UDPServer::listen()'
main.cpp:(.text+0x400): undefined reference to `TCPClient::TCPClient(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x40c): undefined reference to `TCPClient::make_connection()'
main.cpp:(.text+0x42b): undefined reference to `TCPClient::send_message(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x492): undefined reference to `TCPServer::TCPServer(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x4b9): undefined reference to `TCPServer::socket_bind()'
CMakeFiles/cpp_sockets.dir/main.cpp.o: In function `UDPClient::~UDPClient()':
main.cpp:(.text._ZN9UDPClientD2Ev[_ZN9UDPClientD5Ev]+0x14): undefined reference to `Socket::~Socket()'
CMakeFiles/cpp_sockets.dir/main.cpp.o: In function `UDPServer::~UDPServer()':
main.cpp:(.text._ZN9UDPServerD2Ev[_ZN9UDPServerD5Ev]+0x14): undefined reference to `Socket::~Socket()'
CMakeFiles/cpp_sockets.dir/main.cpp.o: In function `TCPClient::~TCPClient()':
main.cpp:(.text._ZN9TCPClientD2Ev[_ZN9TCPClientD5Ev]+0x14): undefined reference to `Socket::~Socket()'
CMakeFiles/cpp_sockets.dir/main.cpp.o: In function `TCPServer::~TCPServer()':
main.cpp:(.text._ZN9TCPServerD2Ev[_ZN9TCPServerD5Ev]+0x14): undefined reference to `Socket::~Socket()'
collect2: error: ld returned 1 exit status
src/project/CMakeFiles/cpp_sockets.dir/build.make:94: recipe for target '../bin/cpp_sockets' failed
make[2]: *** [../bin/cpp_sockets] Error 1
CMakeFiles/Makefile2:85: recipe for target 'src/project/CMakeFiles/cpp_sockets.dir/all' failed
make[1]: *** [src/project/CMakeFiles/cpp_sockets.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
main.cpp file looks like:
#include "project/udp_server.h"
#include "project/udp_client.h"
#include "project/tcp_client.h"
Why would the linker not be able to find the references like this?

It looks like your src/project/CMakeLists.txt neglects to specify the other cpp files, like udp_server.cpp and udp_client.cpp, as dependencies of the executable cpp_sockets. You need to do this in order for CMake to compile those source files; it won't automatically figure out to compile them just because you have included their corresponding headers. In fact, the add_executable declaration doesn't need to say anything about the headers, because the include_directories command takes care of that.
Given the header files that your main.cpp depends on, its add_executable line should look like this:
add_executable(cpp_sockets main.cpp udp_server.cpp udp_client.cpp tcp_client.cpp)

Related

Linking waLBerla to my own code using Cmake

I want to play around with waLBerla (website and gitlab), which is a C++ library that can be used to simulate certain physical behavior, like fluid dynamics using the Lattice Boltzmann method, but having major difficulties on how to properly set up my CMakeLists.txt, as I don't have much experience with that.
I followed the instructions to install the library, using some of the dependencies like OpenMP, CUDA and OpenMESH, which went fine.
But when trying to compile for example one of the tutorials, I just can't get it to work. So far I have the following Cmake file, where I manually list all the static libraries that have been build when compiling waLBerla:
CMAKE_MINIMUM_REQUIRED (VERSION 3.20)
set (CMAKE_CXX_STANDARD 20)
PROJECT (sugar_dissolving)
add_executable(${PROJECT_NAME} main.cpp)
find_package( waLBerla REQUIRED)
find_package(MPI REQUIRED)
find_package(OpenMP REQUIRED)
target_link_libraries(sugar_dissolving PRIVATE OpenMP::OpenMP_CXX)
target_link_libraries(sugar_dissolving PRIVATE
${MPI_LIBRARIES}
/usr/local/lib/libcore.a
/usr/local/lib/libblockforest.a
/usr/local/lib/liblbm.a
/usr/local/lib/libboundary.a
/usr/local/lib/libdomain_decomposition.a
/usr/local/lib/libblas.a
/usr/local/lib/libfield.a
/usr/local/lib/libexecutiontree.a
/usr/local/lib/liblapack.a
/usr/local/lib/libgeometry.a
/usr/local/lib/libmesh.a
/usr/local/lib/libgather.a
/usr/local/lib/libtimeloop.a
/usr/local/lib/libvtk.a
/usr/local/lib/libcuda.a
/usr/local/lib/libgui.a
/usr/local/lib/liblbm_mesapd_coupling.a
/usr/local/lib/libmesa_pd.a
/usr/local/lib/libpde.a
/usr/local/lib/libpe.a
/usr/local/lib/libpe_coupling.a
/usr/local/lib/libpostprocessing.a
/usr/local/lib/libpython_coupling.a
/usr/local/lib/libsqlite.a
<private>/walberla/build/extern/lodepng/liblodepng.a
)
waLBerla exports a package when building it, so I am using find_package(). At first it couldn't find the waLBerla-config.cmake file, so I manually copied it into the package registery, but I think this is not the way to do it? In general, it feels very weird to have to manually list all the the libraries. In this case I don't know if I can know in advance which libraries I need.
It does manage to compile the tutorial, i.e. the header files are found correctly, but then it fails at the linking stage. It knows where to find most functions, but for some reason some of the math functions, which are in libcore.a, don't get found properly. Similarly for some MPI functions, defined by waLBerla:
/usr/bin/ld: /usr/local/lib/libblockforest.a(Initialization.cpp.o): in function `walberla::blockforest::calculateCellDistribution(walberla::math::Vector3<unsigned long> const&, unsigned long, walberla::math::Vector3<unsigned long>&, walberla::math::Vector3<unsigned long>&)':
Initialization.cpp:(.text+0xbfc): undefined reference to `walberla::math::getFactors(unsigned long, unsigned long, std::vector<double, std::allocator<double> > const&)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(SetupBlockForest.cpp.o): in function `walberla::blockforest::SetupBlockForest::getNextBlock(walberla::blockforest::SetupBlock const*) const':
SetupBlockForest.cpp:(.text+0x117f): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(SetupBlockForest.cpp.o): in function `walberla::blockforest::SetupBlockForest::getNextBlock(walberla::blockforest::SetupBlock const*)':
SetupBlockForest.cpp:(.text+0x1287): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(SetupBlockForest.cpp.o): in function `walberla::blockforest::SetupBlockForest::getBlock(walberla::blockforest::BlockID const&) const':
SetupBlockForest.cpp:(.text+0x132d): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x13b8): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x142c): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(SetupBlockForest.cpp.o):SetupBlockForest.cpp:(.text+0x3e06): more undefined references to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)' follow
/usr/bin/ld: /usr/local/lib/libblockforest.a(SetupBlockForest.cpp.o): in function `walberla::blockforest::SetupBlockForest::toStream(std::ostream&) const':
SetupBlockForest.cpp:(.text+0x9379): undefined reference to `walberla::math::Sample::variance(double) const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x93cd): undefined reference to `walberla::math::Sample::relativeStdDeviation() const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x95d9): undefined reference to `walberla::math::Sample::variance(double) const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x962d): undefined reference to `walberla::math::Sample::relativeStdDeviation() const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x9851): undefined reference to `walberla::math::Sample::variance(double) const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x98a8): undefined reference to `walberla::math::Sample::relativeStdDeviation() const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x9f00): undefined reference to `walberla::math::Sample::variance(double) const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x9f53): undefined reference to `walberla::math::Sample::relativeStdDeviation() const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0xa160): undefined reference to `walberla::math::Sample::variance(double) const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0xa1b3): undefined reference to `walberla::math::Sample::relativeStdDeviation() const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0xa3d0): undefined reference to `walberla::math::Sample::variance(double) const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0xa426): undefined reference to `walberla::math::Sample::relativeStdDeviation() const'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0xa576): undefined reference to `walberla::real_comparison::Epsilon<double>::value'
/usr/bin/ld: /usr/local/lib/libblockforest.a(SetupBlockForest.cpp.o): in function `walberla::blockforest::SetupBlockForest::init(walberla::math::GenericAABB<double> const&, unsigned long, unsigned long, unsigned long, bool, bool, bool, walberla::Set<walberla::uid::UID<walberla::uid::suidgenerator::S> > const&)':
SetupBlockForest.cpp:(.text+0x14267): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x1454a): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: SetupBlockForest.cpp:(.text+0x159c1): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(StructuredBlockForest.cpp.o): in function `walberla::blockforest::StructuredBlockForest::blockExists(walberla::cell::Cell const&, unsigned long) const':
StructuredBlockForest.cpp:(.text+0x24d): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(StructuredBlockForest.cpp.o): in function `walberla::blockforest::StructuredBlockForest::getBlockID(walberla::domain_decomposition::IBlockID&, walberla::cell::Cell const&, unsigned long) const':
StructuredBlockForest.cpp:(.text+0x410): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(BlockForest.cpp.o):BlockForest.cpp:(.text+0x72a0): more undefined references to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)' follow
/usr/bin/ld: /usr/local/lib/libblockforest.a(BlockForest.cpp.o): in function `walberla::blockforest::BlockForest::constructBlockInformation()':
BlockForest.cpp:(.text+0x1c62a): undefined reference to `walberla::mpi::allGathervBuffer(walberla::mpi::GenericSendBuffer<unsigned char, walberla::mpi::OptimalGrowth> const&, walberla::mpi::GenericRecvBuffer<unsigned char>&, ompi_communicator_t*)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(BlockForest.cpp.o): in function `void walberla::blockforest::BlockID::toBuffer<walberla::mpi::GenericSendBuffer<unsigned char, walberla::mpi::OptimalGrowth> >(walberla::mpi::GenericSendBuffer<unsigned char, walberla::mpi::OptimalGrowth>&) const':
BlockForest.cpp:(.text._ZNK8walberla11blockforest7BlockID8toBufferINS_3mpi17GenericSendBufferIhNS3_13OptimalGrowthEEEEEvRT_[_ZNK8walberla11blockforest7BlockID8toBufferINS_3mpi17GenericSendBufferIhNS3_13OptimalGrowthEEEEEvRT_]+0x1a): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(BlockForest.cpp.o): in function `std::vector<walberla::uid::UID<walberla::uid::suidgenerator::S>, std::allocator<walberla::uid::UID<walberla::uid::suidgenerator::S> > > walberla::mpi::allReduceSet<walberla::uid::UID<walberla::uid::suidgenerator::S> >(std::vector<walberla::uid::UID<walberla::uid::suidgenerator::S>, std::allocator<walberla::uid::UID<walberla::uid::suidgenerator::S> > >, walberla::mpi::SetOperation, ompi_communicator_t*, int)':
BlockForest.cpp:(.text._ZN8walberla3mpi12allReduceSetINS_3uid3UIDINS2_13suidgenerator1SEEEEESt6vectorIT_SaIS8_EESA_NS0_12SetOperationEP19ompi_communicator_ti[_ZN8walberla3mpi12allReduceSetINS_3uid3UIDINS2_13suidgenerator1SEEEEESt6vectorIT_SaIS8_EESA_NS0_12SetOperationEP19ompi_communicator_ti]+0x3b2): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(BlockReconstruction.cpp.o): in function `walberla::blockforest::BlockReconstruction::reconstructAABB(walberla::math::GenericAABB<double>&, walberla::blockforest::BlockID const&, walberla::math::GenericAABB<double> const&, unsigned long, unsigned long, unsigned long, unsigned long)':
BlockReconstruction.cpp:(.text+0x8d): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: BlockReconstruction.cpp:(.text+0x129): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: BlockReconstruction.cpp:(.text+0x4eb): undefined reference to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)'
/usr/bin/ld: /usr/local/lib/libblockforest.a(PhantomBlockForest.cpp.o):PhantomBlockForest.cpp:(.text+0x6586): more undefined references to `unsigned long walberla::math::uintMSBPosition<unsigned long>(unsigned long)' follow
/usr/bin/ld: /usr/local/lib/libdomain_decomposition.a(BlockStorage.cpp.o): in function `walberla::domain_decomposition::BlockStorage::loadBlockData(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, walberla::selectable::SetSelectableObject<std::shared_ptr<walberla::domain_decomposition::internal::BlockDataHandlingWrapper>, walberla::uid::UID<walberla::uid::suidgenerator::S> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
BlockStorage.cpp:(.text+0x31cf): undefined reference to `walberla::mpi::readMPIIO(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, walberla::mpi::GenericRecvBuffer<unsigned char>&)'
/usr/bin/ld: /usr/local/lib/libdomain_decomposition.a(BlockStorage.cpp.o): in function `walberla::domain_decomposition::BlockStorage::saveBlockData(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, walberla::domain_decomposition::BlockDataID const&)':
BlockStorage.cpp:(.text+0x5f8d): undefined reference to `walberla::mpi::writeMPIIO(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, walberla::mpi::GenericSendBuffer<unsigned char, walberla::mpi::OptimalGrowth>&)'
/usr/bin/ld: /usr/local/lib/libdomain_decomposition.a(IBlock.cpp.o): in function `walberla::domain_decomposition::IBlock::operator==(walberla::domain_decomposition::IBlock const&) const':
IBlock.cpp:(.text+0x1d7): undefined reference to `walberla::real_comparison::Epsilon<double>::value'
/usr/bin/ld: /usr/local/lib/libdomain_decomposition.a(StructuredBlockStorage.cpp.o): in function `walberla::domain_decomposition::StructuredBlockStorage::isCellAlignedAABB(walberla::math::GenericAABB<double> const&, unsigned long) const':
StructuredBlockStorage.cpp:(.text+0x721): undefined reference to `walberla::real_comparison::Epsilon<double>::value'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/sugar_dissolving.dir/build.make:126: sugar_dissolving] Error 1
make[1]: *** [CMakeFiles/Makefile2:2335: CMakeFiles/sugar_dissolving.dir/all] Error 2
make: *** [Makefile:136: all] Error 2
When building waLBerla, it also compiled these tutorials, so I know I have all the necessary packages and libraries, but how do I get it to compile, preferably in a modern Cmake way, in a different directory.
For completeness, here is the output of tree:
.
├── build
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── 3.20.0
│   │   │   ├── CMakeCCompiler.cmake
│   │   │   ├── CMakeCXXCompiler.cmake
│   │   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   │   ├── CMakeSystem.cmake
│   │   │   ├── CompilerIdC
│   │   │   │   ├── a.out
│   │   │   │   ├── CMakeCCompilerId.c
│   │   │   │   └── tmp
│   │   │   └── CompilerIdCXX
│   │   │   ├── a.out
│   │   │   ├── CMakeCXXCompilerId.cpp
│   │   │   └── tmp
│   │   ├── cmake.check_cache
│   │   ├── CMakeDirectoryInformation.cmake
│   │   ├── CMakeError.log
│   │   ├── CMakeOutput.log
│   │   ├── CMakeRuleHashes.txt
│   │   ├── CMakeTmp
│   │   ├── FindMPI
│   │   │   ├── test_mpi_C.bin
│   │   │   ├── test_mpi.cpp
│   │   │   └── test_mpi_CXX.bin
│   │   ├── FindOpenMP
│   │   │   ├── ompver_C.bin
│   │   │   ├── ompver_CXX.bin
│   │   │   ├── OpenMPCheckVersion.c
│   │   │   ├── OpenMPCheckVersion.cpp
│   │   │   ├── OpenMPTryFlag.c
│   │   │   └── OpenMPTryFlag.cpp
│   │   ├── Makefile2
│   │   ├── Makefile.cmake
│   │   ├── Progress
│   │   │   └── count.txt
│   │   ├── progress.marks
│   │   ├── sugar_dissolving.dir
│   │   │   ├── build.make
│   │   │   ├── cmake_clean.cmake
│   │   │   ├── compiler_depend.internal
│   │   │   ├── compiler_depend.make
│   │   │   ├── compiler_depend.ts
│   │   │   ├── DependInfo.cmake
│   │   │   ├── depend.make
│   │   │   ├── flags.make
│   │   │   ├── link.txt
│   │   │   ├── main.cpp.o
│   │   │   ├── main.cpp.o.d
│   │   │   └── progress.make
│   │   └── TargetDirectories.txt
│   ├── cmake_install.cmake
│   ├── compile_commands.json
│   └── Makefile
├── CMakeLists.txt
└── main.cpp
Many thanks!
En example project structure can be found here.
For completeness, the file structure looks like:
example_app/
├── apps
│   ├── CMakeLists.txt (1)
│   └── example_app
│   ├── CMakeLists.txt (2)
│   └── ExampleApp.cpp
├── CMakeLists.txt (3)
├── FindwaLBerla.cmake (4)
├── README
├── src
│   └── CMakeLists.txt (5)
└── tests
└── CMakeLists.txt (6)
Going from top to bottom, the content of the CMakeLists.txt is
(1):
add_subdirectory( example_app )
(2):
waLBerla_link_files_to_builddir( *.prm *.py)
waLBerla_add_executable ( NAME ExampleApp
FILES ExampleApp.cpp
DEPENDS blockforest core field lbm geometry timeloop gui mesh)
(3):
CMAKE_MINIMUM_REQUIRED (VERSION 3.0)
PROJECT ( your_project_name )
enable_testing()
include_directories( src )
include_directories ( ${your_project_name_BINARY_DIR}/src )
# Extends cmake module path - so that FindwaLBerla.cmake in the current directory is found
set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${your_project_name_SOURCE_DIR} )
find_package( waLBerla )
add_subdirectory( src )
add_subdirectory( apps )
add_subdirectory( tests )
(4):
set( WALBERLA_DIR WALBERLA_DIR-NOTFOUND CACHE PATH "waLBerla path" )
if ( WALBERLA_DIR )
# WALBERLA_DIR has to point to the waLBerla source directory
# this command builds waLBerla (again) in the current build directory in the subfolder "walberla" (second argument)
add_subdirectory( ${WALBERLA_DIR} walberla )
waLBerla_import()
# Adds the 'src' and 'tests' directory of current app
list( APPEND WALBERLA_MODULE_DIRS "${CMAKE_SOURCE_DIR}/src" "${CMAKE_SOURCE_DIR}/tests" )
list( REMOVE_DUPLICATES WALBERLA_MODULE_DIRS )
set ( WALBERLA_MODULE_DIRS ${WALBERLA_MODULE_DIRS} CACHE INTERNAL "All folders that contain modules or tests" )
else()
message( FATAL_ERROR "waLBerla not found - Use 'cmake -DWALBERLA_DIR=path_to_waLBerla_sources pathToApplicationSources' " )
endif()
(5) + (6):
#add_subdirectory( name_of_your_module_subfolder )

CMake undefined reference to class

I'm trying to compile a project using CMake, but I'm getting undefined references to class functions that I have created. If I create a Makefile by hand, everything compiles fine. But when I use CMake, I'm getting undefined reference errors.
This is the directory structure:
.
├── build
├── CMakeLists.txt
├── info
│   ├── indexer.pdf
│   └── search.pdf
├── Makefile
├── sample
│   ├── 1
│   │   └── b.txt
│   ├── 2
│   │   └── c.txt
│   ├── 3
│   │   └── d.txt
│   └── a.txt
├── src
│   ├── cpp
│   │   ├── index.cpp
│   │   └── record.cpp
│   ├── h
│   │   ├── index.h
│   │   └── record.h
│   └── main.cpp
├── tests
│   └── a
└── todo.txt
CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
# Project Name
PROJECT(indexer CXX)
# Binary dir
# Built in CMake variables:
# CMAKE_SOURCE_DIR: the directory where cmake was executed
# CMAKE_BINARY_DIR: where the output will go
# EXECUTABLE_OUTPUT_PATH: common place to put executables if you don't want it to be CMAKE_BINARY_DIR
# LIBRARY_OUTPUT_PATH: common place to put libraries if you don't want it to be CMAKE_BINARY_DIR
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/build)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# Add additional compiler flags
# Built-ins:
# - CMAKE_CXX_FLAGS_DEBUG = -g
# - CMAKE_CXX_FLAGS_RELEASE = -O3 -NDEBUG
set(CMAKE_CXX_FLAGS "-std=c++0x -Wall")
include_directories("${PROJECT_SOURCE_DIR}/src/h")
# Aggregate the sources
file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/src/cpp")
add_executable(indexer "${PROJECT_SOURCE_DIR}/src/main.cpp" ${SOURCES})``
Error:
CMakeFiles/indexer.dir/src/main.cpp.o: In function `parse(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, Index*)':
main.cpp:(.text+0x1b5): undefined reference to `Record::Record(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int)'
main.cpp:(.text+0x1ee): undefined reference to `Index::add(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, Record)'
CMakeFiles/indexer.dir/src/main.cpp.o: In function `main':
main.cpp:(.text+0x77d): undefined reference to `Index::Index()'
main.cpp:(.text+0x84b): undefined reference to `Index::print()'
collect2: error: ld returned 1 exit status
CMakeFiles/indexer.dir/build.make:94: recipe for target 'indexer' failed
make[2]: *** [indexer] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/indexer.dir/all' failed
make[1]: *** [CMakeFiles/indexer.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
Can someone tell me what I'm doing wrong here?
Your issue is with the line
file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/src/cpp")
This will set the SOURCES variable to a file named cpp in the src directory. I think you meant something like
file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/src/cpp/*.cpp")
This will catch all files that end with the extension .cpp, and put them into the SOURCES variable.
Note: I don't think you will need to pass "${PROJECT_SOURCE_DIR}/src/main.cpp" as an argument to create_executable, since your SOURCES variable should already contain the main.cpp.

CMake: undefined reference to

I use CMake 3.5.2. When trying to build my C++ code I get the following error:
[100%] Linking CXX executable SomeExecutable
CMakeFiles/SomeExecutable.dir/Common/src/FunctionOne.cpp.o: In function `FunctionOne::FunctionOne(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double, double, unsigned int, bool)':
FunctionOne.cpp:(.text+0x490): undefined reference to `Helper::initLevel(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)'
The program doesn't find Helper::initLevel() in myLib.so. How do I fix it?
CMakeLists.txt: (shortened for brevity)
cmake_minimum_required(VERSION 3.0)
project(ProjectName)
add_definitions(-std=c++11)
add_definitions(-Wall)
add_definitions(-O2)
link_directories(/usr/local/lib)
add_executable(SomeExecutable SomeExecutable.cpp ${FunctionOne} ${FunctionTwo})
target_link_libraries(SomeExecutable -pthread -lboost_thread ${Boost_LIBRARIES} myLib armadillo)
File structure (shortened for brevity):
├── bin
├── CMakeCache.txt
├── cmake_install.cmake
├── CMakeLists.txt
├── Common
│   ├── include
│   │   ├── dataContainer.h
│   │   ├── FunctionOne.h
│   │   ├── FunctionTwo.h
│   └── src
│   ├── FunctionOne.cpp
│   └── FunctionTwo.cpp
├── SomeExecutable.cpp
├── myLib
│   ├── example.cpp
│   ├── include
│   │   ├── Config.h
│   │   ├── Helper.h
│   ├── libmyLib.so
UPDATE:
myLib/include/Config.h:
Namespace Helper {
[...]
Level* initLevel(const std::string& jsonLvlPath, bool twiceSpatPts = false);
[..]
}
UPDATE 2:
kepj#laptop:~/ProjectName$ make VERBOSE=1
/usr/bin/cmake -E cmake_link_script CMakeFiles/SomeExecutable.dir/link.txt --verbose=1
/usr/bin/c++ CMakeFiles/SomeExecutable.dir/SomeExecutable.cpp.o CMakeFiles/SomeExecutable.dir/Common/src/FunctionOne.cpp.o CMakeFiles/SomeExecutable.dir/Common/src/FunctionTwo.cpp.o SomeExecutable -L/usr/local/lib -rdynamic -pthread -lboost_thread -lboost_system -lboost_filesystem -lmyLib -lsymbolicc++ -lmatio -larmadillo -Wl,-rpath,/usr/local/lib
CMakeFiles/SomeExecutable.dir/Common/src/FunctionTwo.cpp.o: In function `FunctionTwo::FunctionTwo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double, double, unsigned int, bool)':
FunctionTwo.cpp:(.text+0x490): undefined reference to `Helper::initLevel(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)'
collect2: error: ld returned 1 exit status
CMakeFiles/SomeExecutable.dir/build.make:174: recipe for target 'SomeExecutable' failed
make[2]: *** [SomeExecutable] Error 1
make[2]: Leaving directory '/home/kepj/ProjectName'
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/SomeExecutable.dir/all' failed
make[1]: *** [CMakeFiles/SomeExecutable.dir/all] Error 2
make[1]: Leaving directory '/home/kepj/ProjectName'
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
So there is technically still not enough information about this issue to answer this question with certainty, but I am going to share how I would debug this isssue, only knowing what is in the question, explaining each step along the way.
Make sure you are linking to the correct myLib.so
This one is pretty explanatory, and would be my best guess as to the root of this problem.
Relevant compiler flags: -L/usr/local/lib -lmyLib
When trying to find the library you specified with the -l argument to your compile command, there is a series of steps that the linker takes:
1. It sees if the argument passed to -l was an absolute path (entire path to the library, ie starting with / on *nix computers or a drive letter on Windows) or just a name. If it is a absolute path, then it knows where it is. In this case, it is just a name, so continue on to step 2.
2. The next place to look is in the paths specified in -L arguments. In this case the only -L argument is to /usr/local/lib so it looks there. This may or may not be where it is found for this specific case. Look in your filesystem to see if the file /usr/local/lib/libmyLib.so exists, and if so make sure that is the version that is most recenpt.
3. Now it searches in configured linker paths. Use the same steps as in step 2 for each of these paths.
This is my guess because there is no reference to your myLib folder in your linker arguments, yet you claim it is in that folder, so I think it is using an out of date myLib.so.
Make sure the .so or .a file actually has the symbol that is undefined
On linux, you can list the symbols defined in a .so file. Make sure the symbol that is resolving to undefined is in there.
If they aren't there, here are the possible causes:
You aren't using all the C++ source files (.cpp) to create your library.
The definition and the declaration don't match:
You forgot to enter namespace Helper before defining the function
You misspelled the function name
The arguments/return type don't match
For member functions, you forgot to include MyClass:: before the function name.
ABI mismatch
(thanks to n.m in the comments for pointing this out)
Because there are multiple implementations (and versions) of the C++ standard library, it is possible that you have an ABI Mismatch.
This means that the standard library that myLib was compiled with is not compatable with the one you are trying to compile your executable with. For example, when you compile myLib with libstdc++ on linux, then go to mac and try to compile your executable, where the standard library is libc++ you will get errors. Why? The signature for anything, for example std::string is not the same. They are different classes entirely, and will cause a signature mismatch while linking.

CLion - cmake undefined reference

I would like to execute a working project with CLion.
So I was trying to emulate the Makefile through cmake but I'm not very good in it. I am sure that the error is inside cmake since the project is working with regular Makefile. Unfortunately, I cannot show a lot information on the project. I hope what I will show would be enough to receive your help.
The project directory structure ( without showing the files ) is shown in the following:
.
├── CMakeLists.txt
├── makefile
├── include
│ ├── data
│ ├── io
│ ├── learning
│ ├── metric
│ ├── scoring
│ └── io
└── src
├── data
├── io
├── learning
├── metric
├── scoring
├── utils
└── main.cc
./CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(Project)
set(DCMAKE_CXX_COMPILER "g++-5")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
find_package(Boost 1.57.0 COMPONENTS program_options system filesystem REQUIRED)
find_package(OpenMP)
if (OPENMP_FOUND)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()
include_directories(${Boost_INCLUDE_DIRS})
include_directories("include")
include_directories("src")
add_executable(Project src/main.cc)
target_link_libraries(Project ${Boost_LIBRARIES})
The project compiles without error, but fails during linking.
Part of the error is reported in the following:
[ 50%] Linking CXX executable Project
CMakeFiles/Project.dir/src/main.cc.o: in function "metric::ir::ir_metric_factory(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned int)":
./include/metric/metricfactory.h:47: undefined reference to "metric::ir::Dcg::NAME_[abi:cxx11]"
./include/metric/metricfactory.h:49: undefined reference to "metric::ir::Ndcg::NAME_[abi:cxx11]"
./include/metric/metricfactory.h:51: undefined reference to "metric::ir::Tndcg::NAME_[abi:cxx11]"
./include/metric/metricfactory.h:53: undefined reference to "metric::ir::Map::NAME_[abi:cxx11]"
CMakeFiles/Project.dir/src/main.cc.o: in function "main":
./src/main.cc:130: undefined reference to "learning::forests::LambdaMart::NAME_[abi:cxx11]"
./src/main.cc:170: undefined reference to "learning::forests::Mart::NAME_[abi:cxx11]"
./src/main.cc:171: undefined reference to "learning::forests::LambdaMart::NAME_[abi:cxx11]"
./src/main.cc:172: undefined reference to "learning::forests::ObliviousMart::NAME_[abi:cxx11]"
./src/main.cc:173: undefined reference to "learning::forests::ObliviousLambdaMart::NAME_[abi:cxx11]"
./src/main.cc:174: undefined reference to "learning::linear::CoordinateAscent::NAME_[abi:cxx11]"
./src/main.cc:175: undefined reference to "learning::forests::Project::NAME_[abi:cxx11]"
./src/main.cc:176: undefined reference to "learning::CustomLTR::NAME_[abi:cxx11]"
./src/main.cc:181: undefined reference to "metric::ir::Dcg::NAME_[abi:cxx11]"
./src/main.cc:182: undefined reference to "metric::ir::Ndcg::NAME_[abi:cxx11]"
./src/main.cc:183: undefined reference to "metric::ir::Tndcg::NAME_[abi:cxx11]"
./src/main.cc:184: undefined reference to "metric::ir::Map::NAME_[abi:cxx11]"
./src/main.cc:247: undefined reference to "metric::ir::Dcg::NAME_[abi:cxx11]"
./src/main.cc:248: undefined reference to "metric::ir::Ndcg::NAME_[abi:cxx11]"
./src/main.cc:249: undefined reference to "metric::ir::Tndcg::NAME_[abi:cxx11]"
./src/main.cc:250: undefined reference to "metric::ir::Map::NAME_[abi:cxx11]"
./src/main.cc:319: undefined reference to "learning::forests::LambdaMart::NAME_[abi:cxx11]"
./src/main.cc:324: undefined reference to "learning::forests::Mart::NAME_[abi:cxx11]"
./src/main.cc:329: undefined reference to "learning::forests::ObliviousMart::NAME_[abi:cxx11]"
./src/main.cc:334: undefined reference to "learning::forests::ObliviousLambdaMart::NAME_[abi:cxx11]"
./src/main.cc:339: undefined reference to "learning::linear::CoordinateAscent::NAME_[abi:cxx11]"
./src/main.cc:346: undefined reference to "learning::linear::CoordinateAscent::CoordinateAscent(unsigned int, double, double, unsigned int, unsigned int)"
./src/main.cc:347: undefined reference to "learning::forests::Project::NAME_[abi:cxx11]"
./src/main.cc:351: undefined reference to "learning::CustomLTR::NAME_[abi:cxx11]"
./src/main.cc:352: undefined reference to "learning::CustomLTR::CustomLTR()"
( other errors lines )
collect2: error: ld returned 1 exit status
make[2]: *** [Project] Error 1
make[1]: *** [CMakeFiles/Project.dir/all] Error 2
make: *** [all] Error 2
Ok, I solve it thanks to the help of Tsyvarev.
./CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(Project)
set(DCMAKE_CXX_COMPILER "g++-5")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
find_package(Boost 1.57.0 COMPONENTS program_options system filesystem REQUIRED)
find_package(OpenMP)
if (OPENMP_FOUND)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()
include_directories(${Boost_INCLUDE_DIRS})
include_directories("include")
file(GLOB_RECURSE SOURCES src/*.cc) #*/
add_executable(Project ${SOURCES})
target_link_libraries(Project ${Boost_LIBRARIES})
where I used file(GLOB_RECURSE SOURCES src/*.cc) to add sources instead of include_directories("src").

CMake: Undefined reference to function

I have following directory structure:
├── build (empty dir)
├── CMakeLists.txt
├── easylogging++.h
├── help.h
├── operation.h
├── operation_list.h
├── operations
│   ├── CMakeLists.txt
│   ├── matchcount.cc
│   └── matchcount.h
└── ops_toolkit.cc
And I am new to CMake and trying to write CMakeLists.txt.
My matchcount.h has a signature whose implementation is in matchcount.cc (as typical C/C++ structure).
Following is my CMakeLists.txt in base directory
cmake_minimum_required(VERSION 2.6)
project(ops_toolkit)
add_subdirectory(operations)
add_executable(ops_toolkit ops_toolkit.cc)
set(CMAKE_CXX_FLAGS "-std=c++0x")
and following is the one in operations directory
include_directories(${ops_toolkit_SOURCE_DIR}/operations)
link_directories(${ops_toolkit_BINARY_DIR}/operations)
set(all_operations_HEADER operations/matchcount.h)
set(all_operations_SOURCES operations/matchcount.cc)
I am getting undefined reference for function signature called int matchcount(int, const char**) and make complains following
dev:~/work/ops_toolkit/build$ make
Scanning dependencies of target ops_toolkit
[100%] Building CXX object CMakeFiles/ops_toolkit.dir/ops_toolkit.cc.o
Linking CXX executable ops_toolkit
CMakeFiles/ops_toolkit.dir/ops_toolkit.cc.o: In function `__static_initialization_and_destruction_0(int, int)':
ops_toolkit.cc:(.text+0x249): undefined reference to `operations::matchcount(int, char const**)'
collect2: ld returned 1 exit status
make[2]: *** [ops_toolkit] Error 1
make[1]: *** [CMakeFiles/ops_toolkit.dir/all] Error 2
make: *** [all] Error 2
Can someone help me with this?
Thanks
The problem comes from the add_subdirectory and its associated CMakeLists.txt (the one in ./operations), which is incorrect, see this SO question for the implications of the add_subdirectory command.
I also advise you to put include_directories and link_directories in the main CMake file, for clarity.