I am trying to learn cmake. My goal is to create a library and compile some example program with it.
my project tree
/home/username/project/--|
|-- CMakeLists.txt
|-- example/--|
| |-- CMakeLists.txt
| |-- main.cpp
|
|--fraction/--|
| |--CMakeLists.txt
| |--include/--|
| | |--fraction.h
| |
| |--src/------|
| | |--fraction.cpp
|
|--operation/-|
| |--CMakeLists.txt
| |--include/--|
| | |--operation.h
| |
| |--src/------|
| | |--operation.cpp
in fraction.h
#include <iostream>
using namespace std;
int least_common_multiple(int d1, int d2)
{
int large = d1 > d2 ? d1 : d2;
int small = large == d1 ? d2 : d1;
for (int i = 1; ; i++)
{
if ((large*i) % small == 0)
{
large = large*i;
break;
}
}
return large;
}
class fraction
{
private:
int numerator, denominator;
public:
fraction(int numr = 1, int denomr = 1);
fraction operator+(fraction &frac);
~fraction();
};
in fraction.cpp
#include "fraction.h"
fraction::fraction(int numr, int denomr) : numerator(numr), denominator(denomr) {}
fraction fraction::operator+(fraction &frac)
{
fraction sum;
sum.numerator = denominator*frac.numerator + numerator*frac.denominator;
sum.denominator = least_common_multiple(denominator, frac.denominator);
return sum;
}
fraction::~fraction() {}
in CMakeLists.txt
inside fraction
set(target fraction)
# Sources
set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include")
set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/src")
# Set the source files to compile
file(GLOB_RECURSE sources ${source_path}/*.cpp)
file(GLOB_RECURSE headers ${include_path}/*.h)
# Build library
add_library(${target} ${sources})
# Add include directories
target_include_directories(${target} PUBLIC ${include_path})
install(FILES ${headers} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${target})
install(TARGETS ${target}
DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
in operation.h
#include "fraction.h"
class operation
{
public:
fraction add(fraction a, fraction b);
~operation();
};
in operation.cpp
#include "operation.h"
fraction operation::add(fraction a, fraction b)
{
return a+b;
}
operation::~operation() { }
in CMakeLists.txt
inside operation
set(target operation)
# Sources
set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include")
set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/src")
# Set the source files to compile
file(GLOB_RECURSE sources ${source_path}/*.cpp)
file(GLOB_RECURSE headers ${include_path}/*.h)
add_library(${target} ${sources})
target_link_libraries(${target} fraction)
# Add include directories
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
install(FILES ${headers} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/${target})
install(TARGETS ${target}
DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
in main.cpp
#include "operation.h"
int main()
{
fraction a(3,5);
fraction b(4,7);
operation ADD;
ADD.add(a,b);
return 0;
}
in CMakeLists.txt
inside example
add_executable(example1 main.cpp)
set(headers ${PROJECT_SOURCE_DIR}/fraction/include ${PROJECT_SOURCE_DIR}/operation/include)
target_include_directories(example1 PRIVATE ${headers})
and in the root CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(demo)
set(CMAKE_BUILD_TYPE "Release")
add_subdirectory(fraction)
add_subdirectory(operation)
add_subdirectory(example)
when I compile with the following commands
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=path/to/build folder inside project ..
make
this error is generated
[ 16%] Building CXX object fraction/CMakeFiles/fraction.dir/src/fraction.cpp.o
[ 33%] Linking CXX static library libfraction.a
[ 33%] Built target fraction
[ 50%] Building CXX object operation/CMakeFiles/operation.dir/src/operation.cpp.o
[ 66%] Linking CXX static library liboperation.a
[ 66%] Built target operation
[ 83%] Building CXX object example/CMakeFiles/example1.dir/main.cpp.o
[100%] Linking CXX executable example1
/usr/bin/ld: CMakeFiles/example1.dir/main.cpp.o: in function `main.cold':
main.cpp:(.text.unlikely+0x4): undefined reference to `fraction::~fraction()'
/usr/bin/ld: main.cpp:(.text.unlikely+0xc): undefined reference to `fraction::~fraction()'
/usr/bin/ld: main.cpp:(.text.unlikely+0x14): undefined reference to `operation::~operation()'
/usr/bin/ld: main.cpp:(.text.unlikely+0x1f): undefined reference to `fraction::~fraction()'
/usr/bin/ld: main.cpp:(.text.unlikely+0x27): undefined reference to `fraction::~fraction()'
/usr/bin/ld: CMakeFiles/example1.dir/main.cpp.o: in function `main':
main.cpp:(.text.startup+0x3a): undefined reference to `fraction::fraction(int, int)'
/usr/bin/ld: main.cpp:(.text.startup+0x4c): undefined reference to `fraction::fraction(int, int)'
/usr/bin/ld: main.cpp:(.text.startup+0x85): undefined reference to `operation::add(fraction, fraction)'
/usr/bin/ld: main.cpp:(.text.startup+0x8d): undefined reference to `fraction::~fraction()'
/usr/bin/ld: main.cpp:(.text.startup+0x95): undefined reference to `fraction::~fraction()'
/usr/bin/ld: main.cpp:(.text.startup+0x9d): undefined reference to `fraction::~fraction()'
/usr/bin/ld: main.cpp:(.text.startup+0xa5): undefined reference to `operation::~operation()'
/usr/bin/ld: main.cpp:(.text.startup+0xad): undefined reference to `fraction::~fraction()'
/usr/bin/ld: main.cpp:(.text.startup+0xb5): undefined reference to `fraction::~fraction()'
collect2: error: ld returned 1 exit status
make[2]: *** [example/CMakeFiles/example1.dir/build.make:97: example/example1] Error 1
make[1]: *** [CMakeFiles/Makefile2:186: example/CMakeFiles/example1.dir/all] Error 2
make: *** [Makefile:136: all] Error 2
If I do #include "fraction.h"
inside main.cpp
it generates redifinition error.
How to link everything properly?