I've been following cmake example from here and got a strange problem while linking
Project structure:
├── CMakeLists.txt
├── compile_commands.json -> build/compile_commands.json
├── external
│ └── AudioFile
│ ├── AudioFile.cpp
│ ├── AudioFile.h
│ ├── LICENSE
│ ├── README.md
│ └── tests
└── test.cpp
CMakeLists.txt:
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(torch-sound)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_PREFIX_PATH "/home/nikita/tmp/libtorch")
set(AUDIOFILE_PATH "external/AudioFile")
find_package(Torch REQUIRED)
add_library(audiofile OBJECT "${AUDIOFILE_PATH}/AudioFile.cpp")
target_include_directories(audiofile PUBLIC "${AUDIOFILE_PATH}")
add_executable(mainapp test.cpp)
target_include_directories(mainapp PUBLIC "${AUDIOFILE_PATH}" . )
target_link_libraries(mainapp audiofile "${TORCH_LIBRARIES}")
# if I remove this ^^^^^^^^^^^^^^^^^^^
# the problem disappears
set_property(TARGET mainapp PROPERTY CXX_STANDARD 11)
I get an error while linking:
/usr/bin/c++ -rdynamic CMakeFiles/mainapp.dir/test.cpp.o CMakeFiles/audiofile.dir/external/AudioFile/AudioFile.cpp.o -o mainapp -Wl,-rpath,/home/nikita/tmp/libtorch/lib /home/nikita/tmp/libtorch/lib/libtorch.so -Wl,--no-as-needed,/home/nikita/tmp/libtorch/lib/libcaffe2.so -Wl,--as-needed /home/nikita/tmp/libtorch/lib/libc10.so -lpthread
/usr/bin/ld: CMakeFiles/mainapp.dir/test.cpp.o: in function `main':
test.cpp:(.text+0x56): undefined reference to `AudioFile<double>::load(std::string)'
collect2: error: ld returned 1 exit status
make VERBOSE=1 full output:
https://pastebin.com/tqrLVjZE
test.cpp:
#include <AudioFile.h>
#include <string>
int main () {
AudioFile<double> audio_file;
audio_file.load("/home/nikita/Music/split-track08.wav");
std::cout << "Success!" << std::endl;
return 0;
}
Notice that I don't use libtorch anywhere in code, I only link it, and get the linkage error. HOWEVER, if I remove libtorch from linked libraries, the problem disappears.
It also disappears if I add AudioFile.cpp directly to mainapp in add_executable and get rid of audiofile in CMakeLists.txt
AudioFile<T> is defined in AudioFile.cpp -- a template class with explicit instantiations for double and float in AudioFile.cpp. It comes from this library. And the needed symbol seems to be present in objdump -t -C:
0000000000000000 w F .text._ZN9AudioFileIfE4loadENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE 00000000000002be AudioFile<float>::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
0000000000000000 w F .text._ZN9AudioFileIdE4loadENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE 00000000000002be AudioFile<double>::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
[nikita#x1c build]$ objdump -C -t CMakeFiles/mainapp.dir/test.cpp.o | grep load
0000000000000000 *UND* 0000000000000000 AudioFile<double>::load(std::string)
From the object dump above it seems like mainapp target inherited old ABI from libtorch, while audiofile used the new one. I think the question is now closed.
Related
I wonder how CMake automatically detects that main.cpp depends on header.h
// header.h
int f() {
return 0;
}
// main.cpp
#include "header.h"
int main() {
return f();
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(Cppref)
add_executable(main main.cpp)
When I run cmake . -B build it creates the following make target in ./build/CMakeFiles/main.dir/build.make
CMakeFiles/main.dir/main.cpp.o: CMakeFiles/main.dir/compiler_depend.ts
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/nikolay/Cpp/Train/Cppref/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building CXX object CMakeFiles/main.dir/main.cpp.o"
/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d -o CMakeFiles/main.dir/main.cpp.o -c /home/nikolay/Cpp/Train/Cppref/main.cpp
Pay attention to the -MD compiler option, as
it is used to dump dependencies visible to the preprocessor.
So after the first build it will create ./build/CMakeFiles/main.dir/main.cpp.o.d with the following content
CMakeFiles/main.dir/main.cpp.o: /home/nikolay/Cpp/Train/Cppref/main.cpp \
/home/nikolay/Cpp/Train/Cppref/header.h
So whenever you change header.h, the target main.o will be rebuilt.
I'm having issues linking my project together using cmake.
The project consists of a library, "mylib", and an executable, "mybin", which is linked with it. The structure is the following:
.
├── CMakeLists.txt
├── include
│ ├── mylib.h
│ ├── entities
│ │ ├── entities.h
│ │ ├── entityA.h
│ │ └── entityB.h
│ └── shapes
│ ├── shapes.h
│ ├── shapeA.h
│ └── entityB.h
└── src
├── main.cpp
├── entities
│ ├── entityA.cpp
│ └── entityB.cpp
└── shapes
├── shapeA.cpp
└── entityB.cpp
Where mylib uses all .cpp and .h files (except from main.cpp) to create a static library, and mybin uses main.cpp and links with mylib.h. mylib.h pulls the other header files from the include directory.
Right now, my CMakeLists.txt looks like this:
cmake_minimum_required(VERSION 3.13)
project(myproject VERSION 1.1.0 LANGUAGES C CXX)
add_library(mylib
src/entities/entityA.cpp
src/entities/entityB.cpp
src/shapes/shapeA.cpp
src/shapes/shapeB.cpp
include/mylib.h
include/entities/entities.h
include/entities/entitiesA.h
include/entities/entitiesB.h
include/shapes/shapes.h
include/shapes/shapeA.h
include/shapes/shapeB.h
)
target_include_directories(mylib PUBLIC include)
target_link_libraries(mylib PUBLIC)
target_compile_features(mylib PRIVATE cxx_std_11)
add_executable(mybin src/main.cpp)
target_link_libraries(mybin PRIVATE mylib)
target_compile_features(mybin PRIVATE cxx_std_11)
When I try to build my code, with
mkdir build
cd build
cmake ..
make
The library builds fine, but I get linking errors while the executable is building:
/usr/bin/ld: shapeA.cpp:(.text+0x344): undefined reference to `MyLib::Entities::EntityA::normalize_inplace()'
Not sure how to fix this, I tried to follow numeral tutorials and looking at other issues here and examples, but couldn't get to fix it. The actual code is in my github, in the "cmake" branch.
Thank you very much.
EDIT
The linking error I copied above is used in the src/shapes/shapeA.cpp file:
#include "shapes/shapeA.h"
#include <algorithm>
using MyLib::Entities::EntityA;
Mylib::Shapes::ShapeA::ShapeA() {}
Mylib::Shapes::ShapeA::~ShapeA(){}
bool Mylib::Shapes::ShapeA::intersect(const EntityA &entity) const {
const EntityA invdir = (EntityA(1.0, 1.0, 1.0) + entity).normalize_inplace();
return true;
}
It is defined in src/entities/entityA.cpp :
#include "entities/EntityA.h"
using MyLib::Entities::EntityA;
EntityA::EntityA(double a, double b, double c) :
a_(a), b_(b), c_(c) {}
EntityA::~EntityA(){}
EntityA EntityA::normalize_inplace(){
const double tot = std::sqrt(a_*a_ + b_*b_ + c_*c_);
a_ /= tot;
b_ /= tot;
c_ /= tot;
return EntityA(1.0, 1.0, 1.0);
}
EntityA EntityA::operator+(EntityA other) {
return EntiryA(a_ + other.a_, b_ + other.b_, c_ + other.c_);
}
There are many more linking errors like that one, I think nothing gets linked correctly at all.
Also, I used a makefile previously and all linking was being made correctly.
I think, I may have improperly set up cmake wrong,(or improperly set up cmake for that matter) or I'm bad and rusty at C++ or both and possibly more. I just want to add a header and separate code into a class that loads images for opengl. I also put them in another directory parallel to other libraries in my linux file tree.
The main project folder has the main cmakelists.text file in it it's called "maficengine". Inside it are also a "build" file a "common" file and "external" file and a file called "Mafic", "maficGuiSourceFiles" file and one called "distrib." I think we can just focus on 2. "mafic" and "external". Inside mafic I have one called mafic.cpp which has my main function and is the entry point. Inside external, there is another folder called "myCustomHeaders".. therein lies a file called "loadTexture.cpp" It contains the loadTexture class declaration and definition. Also inside "myCustomHeaders" there is an "include" file which contains "loadTexture.h"... I cannot seem to instanciate an instance of LoadTexture lt; and call the function of loadtexture(); I expect it to at line 187 in mafic.cpp
#cmakelists.text file from main project folder
# CMake entry point
cmake_minimum_required (VERSION 3.0)
project (maficengine )
find_package(OpenGL REQUIRED)
add_library(loaders
external/myCustomHeaders/loadTexture.cpp
external/myCustomHeaders/include/loadTexture.h
)
set(SOURCES external/myCustomHeaders/loadTexture.cpp )
# Compile external dependencies
add_subdirectory (external)
# On Visual 2005 and above, this module can set the debug working directory
cmake_policy(SET CMP0026 OLD)
cmake_policy(SET CMP0079 NEW)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external/rpavlik-cmake-modules-fe2273")
include(CreateLaunchers)
include(MSVCMultipleProcessCompile) # /MP
if(INCLUDE_DISTRIB)
add_subdirectory(distrib)
endif(INCLUDE_DISTRIB)
include_directories(
external/AntTweakBar-1.16/include/
external/glfw-3.1.2/include/
external/glm-0.9.7.1/
external/glew-1.13.0/include/
external/assimp-3.0.1270/include/
external/bullet-2.81-rev2613/src/
external/myCustomHeaders/include
common/
)
set(ALL_LIBS
${OPENGL_LIBRARY}
glfw
GLEW_1130
loaders
)
add_definitions(
-DTW_STATIC
-DTW_NO_LIB_PRAGMA
-DTW_NO_DIRECT3D
-DGLEW_STATIC
-D_CRT_SECURE_NO_WARNINGS
)
# Tutorial 17
add_executable(mageengine
Mafic/mafic.cpp
common/shader.cpp
common/shader.hpp
common/controls.cpp
common/controls.hpp
common/texture.cpp
common/texture.hpp
common/objloader.cpp
common/objloader.hpp
common/vboindexer.cpp
common/vboindexer.hpp
common/quaternion_utils.cpp
common/quaternion_utils.hpp
#Mafic/loadTexture.h
#Mafic/loadTexture.cpp
Mafic/StandardShading.vertexshader
Mafic/StandardShading.fragmentshader
)
target_link_libraries(mageengine
${ALL_LIBS}
ANTTWEAKBAR_116_OGLCORE_GLFW
loaders
)
here's mafic.cpp
#include <loadTexture.h>
int main( void )
{
loadTexture lt;
lt.loadtexture();
}
here's my loadTexture.cpp
class loadTexture
{
public:
loadTexture();
~loadTexture();
void loadtexture(){
fprintf(stdout, "loadtexture does something, that's a positive result for this test");
}
};
and finally my loadTexture.h
[code]
#pragma once
#include <GL/glew.h>
//GLuint image;
void loadtexture();
[/code]
Hoping it would build with no errors but I get ...
aaron#Zog:~/Desktop/maficengine/build$ make
[ 2%] Built target ANTTWEAKBAR_116_OGLCORE_GLFW
[ 2%] Built target GLEW_1130
[ 2%] Built target loaders
[ 6%] Built target glfw
[ 7%] Building CXX object CMakeFiles/mageengine.dir/Mafic/mafic.cpp.o
/home/aaron/Desktop/maficengine/Mafic/mafic.cpp:1:9: warning: #pragma once in main file
#pragma once
^~~~
/home/aaron/Desktop/maficengine/Mafic/mafic.cpp: In function ‘int main()’:
/home/aaron/Desktop/maficengine/Mafic/mafic.cpp:187:1: error: ‘loadTexture’ was not declared in this scope
loadTexture lt;
^~~~~~~~~~~
/home/aaron/Desktop/maficengine/Mafic/mafic.cpp:187:1: note: suggested alternative: ‘loadtexture’
loadTexture lt;
^~~~~~~~~~~
loadtexture
/home/aaron/Desktop/maficengine/Mafic/mafic.cpp:189:2: error: ‘lt’ was not declared in this scope
lt.loadtexture();
^~
CMakeFiles/mageengine.dir/build.make:62: recipe for target 'CMakeFiles/mageengine.dir/Mafic/mafic.cpp.o' failed
make[2]: *** [CMakeFiles/mageengine.dir/Mafic/mafic.cpp.o] Error 1
CMakeFiles/Makefile2:75: recipe for target 'CMakeFiles/mageengine.dir/all' failed
make[1]: *** [CMakeFiles/mageengine.dir/all] Error 2
Makefile:129: recipe for target 'all' failed
make: *** [all] Error 2
aaron#Zog:~/Desktop/maficengine/build$
I'm using cmake with custom GCC(with shared libraries) and during cmake compiler test I get following error:
The C compiler "/path/to/gcc/bin/gcc" is not able to compile a simple test program.
...
/path/to/gcc/x86_64-unknown-linux-gnu/bin/ld:
cannot find -lgcc_s
Here's a simple "testme.cpp" file:
#include <iostream>
int main( int argc, char * argv[] ) {
std::cout << "Hello world" << std::endl;
return 0;
}
and here's a CMakeLists.txt:
cmake_minimum_required(VERSION 2.6.2)
project(testme)
file( GLOB srcs "testme.cpp" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall -std=c++11")
set(CMAKE_LDFLAGS "${CMAKE_LDFLAGS} -L/path/to/gcc/lib/gcc/x86_64-unknown-linux-gnu/lib64")
add_executable(testme ${srcs})
to build with my custom GCC I'm exporting CXX and CC:
export CXX=/path/to/gcc/bin/g++
export CC=/path/to/gcc/bin/gcc
and then hit:
cmake .
make
and the result is that it can't find libgcc_s.so which is located in the "lib/gcc/x86_64-unknown-linux-gnu/lib64" folder.
However, when I invoke gcc like this:
/path/to/gcc/bin/g++ testme.cpp -L/path/to/gcc/lib/gcc/x86_64-unknown-linux-gnu/lib64
it compiles successfully. I've tried to add it to LD_LIBRARY_PATH but that doesn't seem to help.
So, is there a way to pass library path to CMake compiler check?
Chrono Kitsune was sort of right ... /path/to/gcc/x86_64-unknown-linux-gnu/bin/ld was build with "--enable-shared" and libraries where not in systems search path.
The project structure below is a simplified example. I tried to boil it down to the minimal amount of files to reproduce my issue.
.
├── CMakeLists.txt
├── subdir1
│ ├── CMakeLists.txt
│ └── subsubdir1
│ ├── CMakeLists.txt
│ ├── Example.cpp
│ └── Example.h
└── subdir2
├── CMakeLists.txt
├── main.cpp
└── subsubdir1
├── CMakeLists.txt
├── ExampleCreator.cpp
└── ExampleCreator.h
./CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(test)
macro(add_sources)
file (RELATIVE_PATH _relPath "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
foreach (_src ${ARGN})
if (_relPath)
list (APPEND SRCS "${_relPath}/${_src}")
else()
list (APPEND SRCS "${_src}")
endif()
endforeach()
if (_relPath)
# propagate SRCS to parent directory
set (SRCS ${SRCS} PARENT_SCOPE)
endif()
endmacro()
add_subdirectory(subdir1)
add_subdirectory(subdir2)
add_executable(test ${SRCS})
subdir1/CMakeLists.txt
add_subdirectory(subsubdir1)
subdir1/subsubdir1/CMakeLists.txt
add_sources(Example.cpp)
subdir1/subsubdir1/Example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
class Example
{
public:
Example();
virtual ~Example();
};
#endif
subdir1/subsubdir1/Example.cpp
#include <stdio.h>
#include "Example.h"
Example::Example()
{
printf("Inside Example constructor\n");
}
Example::~Example()
{
}
subdir2/CMakeLists.txt
add_subdirectory(subsubdir1)
add_sources(main.cpp)
subdir2/main.cpp
#include "subsubdir1/ExampleCreator.h"
int main(int argc, char** argv)
{
ExampleCreator creator;
return 0;
}
subdir2/subsubdir1/CMakeLists.txt
add_sources(ExampleCreator.cpp)
subdir2/subsubdir1/ExampleCreator.h
#ifndef EXAMPLE_CREATOR_H
#define EXAMPLE_CREATOR_H
class ExampleCreator
{
public:
ExampleCreator();
virtual ~ExampleCreator();
};
#endif
subdir2/subsubdir1/ExampleCreator.cpp
#include "ExampleCreator.h"
#include "../../subdir1/subsubdir1/Example.h"
ExampleCreator::ExampleCreator()
{
Example* ex1 = new Example();
}
ExampleCreator::~ExampleCreator()
{
}
I'm hoping this is a really simple lack of understanding of how CMake handles dependencies. This compiles without error, but fails during linking. The make output below shows that Example.cpp isn't even compiling and I don't understand why.
user>:~/src/test/build$ make
Scanning dependencies of target test
[ 50%] Building CXX object CMakeFiles/test.dir/subdir2/subsubdir1/ExampleCreator.cpp.o
[100%] Building CXX object CMakeFiles/test.dir/subdir2/main.cpp.o
Linking CXX executable test
CMakeFiles/test.dir/subdir2/subsubdir1/ExampleCreator.cpp.o: In function `ExampleCreator::ExampleCreator()':
ExampleCreator.cpp:(.text+0x2b): undefined reference to `Example::Example()'
collect2: ld returned 1 exit status
make[2]: *** [test] Error 1
make[1]: *** [CMakeFiles/test.dir/all] Error 2
make: *** [all] Error 2
All the sources are appended to the SRCS variable in the root CMakeLists.txt file from what I can tell. So, why isn't Example.cpp getting compiled? or linked?
The directory subdir1 doesn't generate a binary. Add this:
project(Example)
add_library(Example Example.cpp)
instead of your add_sources. After this, you need to tell the project that uses it to link against it:
TARGET_LINK_LIBRARIES(subdir2 Example)
If your names differ, document yourself on the functionalities of these commands.