cmake undefined reference to function - cmake

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.

Related

CMake add_subdirectory fails but okay when config is in main CMakeLists.txt

The following CMakeLists.txt builds and runs my executable Sandbox project fine:
cmake_minimum_required(VERSION 3.22)
project(Learning)
add_subdirectory(Engine)
add_executable(Sandbox Sandbox/src/Application.cpp)
target_link_libraries(Sandbox PUBLIC Engine)
But moving the add_executable and target_link_libraries calls for Sandbox into their own CMakeLists.txt and add_subdirectory fails:
cmake_minimum_required(VERSION 3.22)
project(Learning)
add_subdirectory(Engine)
add_subdirectory(Sandbox)
And:
add_executable(Sandbox Application.cpp)
target_link_libraries(Sandbox PUBLIC Engine)
The Engine CMakeLists.txt is:
add_library(Engine SHARED Test.h Test.cpp)
There is a CMakeLists.txt in each of the Engine and Sandbox directories that calls add_subdirectory for the relevant src folder.
Test.h in Engine exports the relevant symbols:
namespace Engine {
__declspec(dllexport) void Print();
}
Which is forward declared in Application.cpp in Sandbox:
namespace Engine {
__declspec(dllimport) void Print();
}
When running, I get the following output:
D:\Learning\cmake-build-debug\Sandbox\src\Sandbox.exe
Process finished with exit code -1073741515 (0xC0000135)
Why does moving this into it's own CMakeLists.txt cause the Sandbox process to finish with an exit code other than zero when run?

CMake linking error with multilevel src directory

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.

CMake -- undefined reference when linking additional libraries which I don't use

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.

Read Karate config from YAML

I would like to define environment-specific properties in a .yml/.yaml file. Therefore I created the following test.yaml:
baseUrl: 'http://localhost:1234'
Next, I wrote this karate-config.js:
function() {
var env = karate.env;
if (!env) {
env = 'test'; // default is test
}
// config = read(env + '.yaml')
var config = read('/home/user/git/karate-poc/src/test/java/test.yaml');
// var config = read('test.yaml');
// var config = read('classpath:test.yaml');
return config;
}
As seen here https://github.com/intuit/karate#reading-files the read() function should be known by Karate, however I'm not sure if this only applies to .feature files or the karate-config.js too.
Unfortunately, none of the above read()s work, as I'm getting this error:
Caused by: com.intuit.karate.exception.KarateException: javascript function call failed: could not find or read file: /home/user/git/karate-poc/src/test/java/test.yaml, prefix: NONE
at com.intuit.karate.Script.evalFunctionCall(Script.java:1602)
I'm sure that the file exists and is readable.
Am I doing something wrong or is my approach not supported? If it's not supported, what would be the recommended way to read the configuration based on the environment from a YAML file (once) in order to use it in (multiple) .feature files?
Thank you very much
Edit: Tree structure of the project:
.
├── build.gradle
├── gradle
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── src
   └── test
   └── java
   ├── karate
   │   └── rest
   │   ├── rest.feature
   │   └── RestRunner.java
   ├── karate-config.js
   └── test.yaml
Run with ./gradlew test
In JS, use the karate object, which is explained here: https://github.com/intuit/karate#the-karate-object
So this should work:
var config = karate.read('classpath:test.yaml');

How to use a swift module in an objective-c module with SwiftPM?

Here is an example of the root directory
├── Package.swift
└── Sources
├── Objc-cli
│   └── main.m
└── Swifty
└── MyStruct.swift
Where the Swifty module is just a simple struct
// MyStruct.swift
public struct MyStruct {
public var text = "Hello, World!"
public init() {
}
}
And in the Objc-cli I try to link the swift module like this.
// main.m
#import <Foundation/Foundation.h>
#import Swifty <---- Not found
int main() {
NSLog(#"Hello from Objc");
return 0;
}
Here is what the Package.swift looks like:
// Package.swift
import PackageDescription
let package = Package(
name: "MyTest",
targets: [
Target(name: "Swifty", dependencies: []),
Target(name: "Objc-cli", dependencies: ["Swifty"]),
]
)
Sadly the compiler doesn't recognise the Swifty module inside the objective-c module. Here is the output:
$ swift build
Compile Swift Module 'Swifty' (1 sources)
Compile Objc-cli main.m
/tmp/TestPackage/Sources/Objc-cli/main.m:10:9: fatal error: module 'Swifty' not found
#import Swifty
~~~~~~~^~~~~~
1 error generated.
<unknown>:0: error: build had 1 command failures
Have I missed something or is it simply impossible for now ?
Right now it's not possible to import Swift module in C module, it only works another way around, import C into Swift.
You can find detailed information at SwiftPM - C language targets