CMake for Halide Hexagon failed while successfully compiled using g++ - cmake

I am writing CMake file for the following command:
g++ --std=c++11 -DLOG2VLEN=7 -DRUN=1 -DASSEMBLY=1 -DBITCODE=1 -I
/home/user/Qualcomm/HALIDE_Tools/2.2.06/Halide/include -fno-rtti -O3 -g
halide_gaussian_hexagon_generate.cpp /home/user/Qualcomm/HALIDE_Tools/2.2.06/Halide/tools/GenGen.cpp
-L/home/user/Qualcomm/HALIDE_Tools/2.2.06/Halide/lib -lHalide -o
bin/halide_gaussian_hexagon_generate -ldl -lpthread -lz -D_GLIBCXX_USE_CXX11_ABI=0
Above compiling works fine but when I wrote it into CMake I got a bunch of error. I am attaching my CMake file here:
cmake_minimum_required(VERSION 3.10)
project(hexagon_polyblur)
set(CMAKE_CXX_STANDARD 11)
set(HEXAGON_DIR $ENV{HALIDE_ROOT})
set(
HEXAGON_FILES_GAUSSIAN
halide_gaussian_hexagon_generate.cpp
${HEXAGON_DIR}/tools/GenGen.cpp # we must include GenGen to compile the generator
)
set(HEXAGON_GEN_GAUSSIAN ${PROJECT_NAME}_hexagon_generate_gaussian)
add_executable(${HEXAGON_GEN_GAUSSIAN} ${HEXAGON_FILES_GAUSSIAN})
target_include_directories(
${HEXAGON_GEN_GAUSSIAN} PRIVATE
${HEXAGON_DIR}/include
${HEXAGON_DIR}/tools
)
target_link_libraries(${HEXAGON_GEN_GAUSSIAN} ${HEXAGON_DIR}/lib/libHalide.so dl pthread z)
target_compile_options(${HEXAGON_GEN_GAUSSIAN} PUBLIC -fno-rtti)
# target_compile_definitions(${HVX_GEN_GAUSSIAN} PRIVATE LOG2VLEN=7 RUN=1 ASSEMBLY=1 BITCODE=1 _GLIBCXX_USE_CXX11_ABI=0)
In CMake, I am using /usr/bin/g++ and /usr/bin/gcc (g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0), which are the same compiler I used for the command line. The ${HEXAGON_DIR} is /home/user/Qualcomm/HALIDE_Tools/2.2.06/Halide. I am not sure why I the CMkae failed here. Part of the error message is shown below:
/usr/bin/ld: CMakeFiles/hexagon_polyblur_hexagon_generate_gaussian.dir /halide_gaussian_hexagon_generate.cpp.o: in function `Halide::Internal::check_introspection(void const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)':
halide_gaussian_hexagon_generate.cpp:(.text+0xaa): undefined reference to `Halide::Internal::Introspection::get_source_location[abi:cxx11]()'
/usr/bin/ld: halide_gaussian_hexagon_generate.cpp:(.text+0xc7): undefined reference to `Halide::Internal::Introspection::get_variable_name(void const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: CMakeFiles/hexagon_polyblur_hexagon_generate_gaussian.dir/halide_gaussian_hexagon_generate.cpp.o: in function `HalideIntrospectionCanary::(anonymous namespace)::TestCompilationUnit::TestCompilationUnit()':
...
Also, when I switch to my original working halide lib that is not for hexagon development, this CMake works. I am not sure whether or not I have a wrong setup in CMake. Any help or suggestion? Thank you!

Have you considered using a more recent version of Halide? Since version 10, we've had good (and constantly improving!) CMake support via find_package.
This should be all you need:
cmake_minimum_required(VERSION 3.16)
project(example)
find_package(Halide REQUIRED)
add_executable(hexagon_gen_gaussian halide_gaussian_hexagon_generate.cpp)
target_link_libraries(hexagon_gen_gaussian PRIVATE Halide::Generator)
Then you can call add_halide_library to run the generator.
Here's a link to our CMake docs for reference: https://github.com/halide/Halide/blob/master/README_cmake.md
You should also look at our example applications (most of them have CMake builds): https://github.com/halide/Halide/tree/master/apps
Feel free to ask any follow-up questions on our GitHub Discussions since I wrote our CMake build/package code.

-L/home/user/Qualcomm/HALIDE_Tools/2.2.06/Halide/lib -lHalide
Translates literally to:
target_link_directories(.... ${THEDIR}/lib)
target_link_libraries(... Halide)
or better:
add_library(halide SHARED IMPORTED)
set_property(TARGET halide PROPERTY
IMPORTED_LOCATION ${THEDIR}/lib/libHalide.so) # or maybe find_library
#
target_link_libraries(... halide) # I wish there would be "target_link_targets"
set(CMAKE_CXX_STANDARD 11)
Better:
set_target_properties(testproject PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED on # maybe also
CXX_EXTENSIONS off
)

Related

Linking problems with yaml-cpp

I am trying to incorporate yaml-cpp into my project.
I have a "Demes" class where I need to parse a YAML file.
This is the relevant method in Demes.cpp:
#include "Demes.hpp"
void Demes::parse(const std::string& fileName)
{
YAML::Node test = YAML::LoadFile(fileName);
}
where Demes.hpp includes the yaml-cpp headers and declares the 'parse' method.
Building with make -VERBOSE=1 (as suggested by #Tsyvarev) gives:
[100%] Linking CXX executable momentspp
cd /home/gvbarroso/Devel/momentspp/build/src && /usr/bin/cmake -E cmake_link_script CMakeFiles/momentspp.dir/link.txt --verbose=1
/usr/bin/c++ -std=c++20 -Weffc++ -Wshadow -Wall -Wextra -ffast-math -O3 -march=native CMakeFiles/momentspp.dir/Log.cpp.o CMakeFiles/momentspp.dir/PolymorphismData.cpp.o CMakeFiles/momentspp.dir/SumStatsLibrary.cpp.o CMakeFiles/momentspp.dir/Drift.cpp.o CMakeFiles/momentspp.dir/Migration.cpp.o CMakeFiles/momentspp.dir/Mutation.cpp.o CMakeFiles/momentspp.dir/Recombination.cpp.o CMakeFiles/momentspp.dir/Epoch.cpp.o CMakeFiles/momentspp.dir/Model.cpp.o CMakeFiles/momentspp.dir/OptimizationWrapper.cpp.o CMakeFiles/momentspp.dir/Demes.cpp.o CMakeFiles/momentspp.dir/main.cpp.o -o momentspp -Wl,-rpath,/home/gvbarroso/.local/lib: /home/gvbarroso/.local/lib/libbpp-phyl3.so.1.0.0 /usr/lib/x86_64-linux-gnu/libboost_iostreams.so.1.74.0 /home/gvbarroso/.local/lib/libbpp-seq3.so.1.0.0 /home/gvbarroso/.local/lib/libbpp-core3.so.1.0.0
/usr/bin/ld: CMakeFiles/momentspp.dir/Demes.cpp.o: in function Demes::parse(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)': Demes.cpp:(.text+0x4c): undefined reference to YAML::LoadFile(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&)'
/usr/bin/ld: Demes.cpp:(.text+0x12c): undefined reference to `YAML::operator<<(std::ostream&, YAML::Node const&)'
collect2: error: ld returned 1 exit status
make[2]: *** [src/CMakeFiles/momentspp.dir/build.make:277: src/momentspp] Error 1
make[2]: Leaving directory '/home/gvbarroso/Devel/momentspp/build'
make[1]: *** [CMakeFiles/Makefile2:125: src/CMakeFiles/momentspp.dir/all] Error 2
make[1]: Leaving directory '/home/gvbarroso/Devel/momentspp/build'
make: *** [Makefile:156: all] Error 2
I am using CMake to build my project, but I am still fairly unfamiliar with it.
EDIT: I forgot to mention that I have two CMakeLists.txt files, one inside src and the other inside the external build.
The start of my CMakeLists.txt file in the external build is:
cmake_minimum_required (VERSION 3.5.0)
project (momentspp CXX)
SET(CMAKE_CXX_FLAGS "-std=c++20 -Weffc++ -Wshadow -Wall -Wextra -ffast-math -O3 -march=native")
And the part of it where I look for yaml-cpp is:
FIND_PACKAGE(yaml-cpp REQUIRED)
IF(yaml-cpp_FOUND)
INCLUDE_DIRECTORIES(${yaml-cpp_INCLUDE_DIRS})
SET(LIBS {yaml-cpp_LIBRARIES})
MESSAGE("-- yaml-cpp libraries found here:")
MESSAGE(" includes: ${yaml-cpp_INCLUDE_DIRS}")
ENDIF()
My full CMakeLists.txt file inside src is:
SET(momentspp_CPP
Log.cpp
PolymorphismData.cpp
SumStatsLibrary.cpp
Drift.cpp
Migration.cpp
Mutation.cpp
Recombination.cpp
Epoch.cpp
Model.cpp
OptimizationWrapper.cpp
Demes.cpp
main.cpp
)
ADD_EXECUTABLE (momentspp ${momentspp_CPP})
SET(momentspp-targets momentspp)
FOREACH (target ${momentspp-targets})
TARGET_LINK_LIBRARIES(${target} ${BPP_LIBS_SHARED} ${BOOST_LIBS_SHARED} ${EIGEN3_LIBS_SHARED} ${yaml-cpp_LIBS_SHARED})
TARGET_LINK_LIBRARIES (${target} ${LIBS})
ENDFOREACH (target)
INSTALL(TARGETS ${momentspp-targets} DESTINATION ${CMAKE_INSTALL_BINDIR})
and this was working prior to the inclusion of yaml-cpp.
This feels like a rather complicated CMake set-up, but I am copying and editing it from a previous project where someone else helped me with it.
How can I fix the linking issue?
I tried looking similar questions around here, but couldn't get their solutions to work for me (apparently those people where not using CMake to build their projects).
Thank you,
Gustavo

Dependency issues linking ImGui, SDL2 to project using CMake

Im having trouble changing my project from Sfml to SDL2+opengl3 rendering. The error im getting with my current CMake setup is ImGui not linking to a subfolder of mine in which i create a SHARED library: UserInterface.
Now i have tried declaring UserInterface a dependency of ImGui library:
(target_link_libraries(UserInterface imgui))
and without it.
I get a few different errors depending on how i set up CMake, but all of them must be wrong:
Without the line i get a bunch of undefined references:
/usr/bin/ld: UserInterface/libUserInterface.so: undefined reference to `ImGui_ImplOpenGL3_Init(char const*)'
/usr/bin/ld: UserInterface/libUserInterface.so: undefined reference to `ImGui::ShowDemoWindow(bool*)'
With that line i get:
/usr/bin/ld: ../libimgui.a(imgui_demo.cpp.o): relocation R_X86_64_PC32 against symbol `GImGuiDemoMarkerCallback' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: bad value
If i then change my UserInterface, and imgui to STATIC libraries i get this error:
/usr/bin/ld: libimgui.a(imgui_impl_opengl3.cpp.o): undefined reference to symbol 'dlclose##GLIBC_2.2.5'
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libdl.so: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
Just to clarify, all these are linking errors when linking CXX executable digitus,
which is my application.
project:
build
CMakeLists.txt
src (folder)
CMakeLists.txt
main.cpp
(all required imgui files)
UserInterface (folder)
CMakeLists.txt
[...]
Action (folder)
[...]
My topmost CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
set (CMAKE_CXX_STANDARD 17)
project(digitus)
set(CMAKE_MODULE_PATH "/usr/local/lib/cmake") # tell cmake where to find find.cmake and config.cmake files
find_package(OpenGL REQUIRED)
find_package(SDL2 REQUIRED)
find_package(GLEW REQUIRED)
find_package(glm REQUIRED)
#include_directories(${SDL2_INCLUDE_DIR}) # add sdl2's include dir
add_subdirectory(src)
This is my CMakeLists.txt inside the src folder:
SET(SOURCES
main.cpp
ApplicationManager.cpp
ApplicationManager.h
[...]
)
SET( IMGUISOURCE
imconfig.h
imgui_demo.cpp
imgui_draw.cpp
imgui_impl_opengl3_loader.h
imgui_impl_opengl3.cpp
imgui_impl_opengl3.h
imgui_impl_sdl.cpp
imgui_impl_sdl.h
imgui_internal.h
imgui_tables.cpp
imgui_widgets.cpp
imgui.cpp
imgui.h
)
add_executable(digitus ${SOURCES})
target_link_libraries(digitus glm::glm )
target_link_libraries(digitus ${CMAKE_DL_LIBS})
add_library(imgui ${IMGUISOURCE})
target_link_libraries(digitus imgui)
add_subdirectory(Action)
add_subdirectory(UserInterface)
#target_link_libraries(UserInterface imgui)
target_link_libraries(digitus UserInterface)
target_link_libraries(digitus Action)
target_link_libraries(digitus SDL2)
target_link_libraries(digitus GLEW::glew)
target_link_libraries(digitus OpenGL::GL )
The CMakeLists.txt inside UserInterface:
Set(USERINTERFACESOURCE
UserInterface.h
UserInterface.cpp
CircuitWindow.h
CircuitWindow.cpp
)
add_library(UserInterface STATIC ${USERINTERFACESOURCE})

How to add Paho Mqtt C and Cpp libraries to a CMakeLists.txt

I am trying to build a cpp project using CMakeLists.txt.
I installed both Paho Mqtt C and Cpp and their Config.cmake can be found at /usr/local/lib/cmake/eclipse-paho-mqtt-c/eclipse-paho-mqtt-cConfig.cmake and /usr/local/lib/cmake/PahoMqttCpp/PahoMqttCppConfig.cmake in my system.
I am trying to compile the async_publish.cpp. For now I could only get it built running the following CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project("Mqtt Test")
#find_package(PahoMqttCpp REQUIRED)
#find_package(eclipse-paho-mqtt-c REQUIRED)
add_executable(mqtt_client mqtt_client.cpp)
target_link_libraries(mqtt_client pthread crypto ssl paho-mqtt3as paho-mqttpp3)
The problem is ... how do I get the libraries from find_package() and pick the right ${whatever_pkg_LIB} and maybe include files?
I tried
target_link_libraries(mqtt_client pthread crypto ssl ${PAHO_MQTT_C_LIBRARIES} ${PAHO_MQTT_CPP_LIBRARIES})
but it didn't work. I got the following error
CMakeFiles/mqtt_client.dir/mqtt_client.cpp.o: In function `main':
mqtt_client.cpp:(.text+0x3ae): undefined reference to `mqtt::async_client::async_client(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int, mqtt::iclient_persistence*)'
mqtt_client.cpp:(.text+0x401): undefined reference to `mqtt::async_client::set_connected_handler(std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>)'
mqtt_client.cpp:(.text+0x445): undefined reference to `mqtt::async_client::set_connection_lost_handler(std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>)'
mqtt_client.cpp:(.text+0x463): undefined reference to `mqtt::connect_options::connect_options()'
mqtt_client.cpp:(.text+0x4b7): undefined reference to `mqtt::message::message(mqtt::buffer_ref<char>, mqtt::buffer_ref<char>, int, bool)'
mqtt_client.cpp:(.text+0x4ee): undefined reference to `mqtt::will_options::will_options(mqtt::message const&)'
mqtt_client.cpp:(.text+0x507): undefined reference to `mqtt::connect_options::set_will(mqtt::will_options const&)'
mqtt_client.cpp:(.text+0x520): undefined reference to `mqtt::connect_options::set_automatic_reconnect(int, int)'
mqtt_client.cpp:(.text+0x561): undefined reference to `mqtt::connect_options::connect_options(mqtt::connect_options const&)'
mqtt_client.cpp:(.text+0x581): undefined reference to `mqtt::async_client::connect(mqtt::connect_options)'
mqtt_client.cpp:(.text+0x6d1): undefined reference to `mqtt::topic::publish(mqtt::buffer_ref<char>)'
mqtt_client.cpp:(.text+0x798): undefined reference to `mqtt::topic::publish(mqtt::buffer_ref<char>)'
mqtt_client.cpp:(.text+0x8d9): undefined reference to `mqtt::async_client::~async_client()'
mqtt_client.cpp:(.text+0xb9c): undefined reference to `mqtt::async_client::~async_client()'
CMakeFiles/mqtt_client.dir/mqtt_client.cpp.o: In function `mqtt::async_client::disconnect()':
mqtt_client.cpp:(.text._ZN4mqtt12async_client10disconnectEv[_ZN4mqtt12async_client10disconnectEv]+0x45): undefined reference to `mqtt::disconnect_options::disconnect_options()'
collect2: error: ld returned 1 exit status
CMakeFiles/mqtt_client.dir/build.make:95: recipe for target 'mqtt_client' failed
make[2]: *** [mqtt_client] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/mqtt_client.dir/all' failed
make[1]: *** [CMakeFiles/mqtt_client.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
this is the CMakeLists.txt I use to make my project
cmake_minimum_required(VERSION 3.1) set(CMAKE_CXX_STANDARD 20)
project(Farm_interface)
include_directories(${PROJECT_SOURCE_DIR}/include)
add_executable(Farm.exe src/main.cpp src/subscriber.cpp)
target_link_libraries( Farm.exe paho-mqttpp3 paho-mqtt3as pthread)

Pthread and introspection library linking with Halide generators fails

I tried to setup a three layer convolution generator pipeline. Build is failing at linking step.
Example followed in apps/wavelet
running make in build directory results in the following error:
[ 87%] Linking CXX executable conv-3
CMakeFiles/conv-3.dir/main.cpp.o: In function `Halide::Internal::check_introspection(void const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)':
main.cpp:(.text+0xa6): undefined reference to `Halide::Internal::Introspection::get_source_location[abi:cxx11]()'
main.cpp:(.text+0xc3): undefined reference to `Halide::Internal::Introspection::get_variable_name(void const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
CMakeFiles/conv-3.dir/main.cpp.o: In function `HalideIntrospectionCanary::(anonymous namespace)::TestCompilationUnit::TestCompilationUnit()':
main.cpp:(.text+0xa6a): undefined reference to `Halide::Internal::Introspection::test_compilation_unit(bool (*)(bool (*)(void const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)), bool (*)(void
const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&), void (*)())'
./genfiles/halide_rt_host/halide_rt_host.a(halide_rt_host.a.o): In function `halide_spawn_thread':
posix_allocator.cpp:(.text.halide_spawn_thread+0x3d): undefined reference to `pthread_create'
./genfiles/halide_rt_host/halide_rt_host.a(halide_rt_host.a.o): In function `halide_join_thread':
posix_allocator.cpp:(.text.halide_join_thread+0x1a): undefined reference to `pthread_join'
collect2: error: ld returned 1 exit status
CMakeFiles/conv-3.dir/build.make:96: recipe for target 'conv-3' failed
make[2]: *** [conv-3] Error 1
CMakeFiles/Makefile2:230: recipe for target 'CMakeFiles/conv-3.dir/all' failed
make[1]: *** [CMakeFiles/conv-3.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
CMakeLists.txt
project(three_layer_conv)
cmake_minimum_required(VERSION 3.1.3)
set(HALIDE_DISTRIB_DIR "/home/user/workspace/Halide/distrib")
include(/home/user/workspace/Halide/distrib/halide.cmake)
# Define the wavelet app
add_executable(conv-3 "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp")
set_target_properties(conv-3 PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO)
target_include_directories(conv-3 PRIVATE "${HALIDE_INCLUDE_DIR}" "${HALIDE_TOOLS_DIR}")
# Define a halide_library() for each generator we have, and link each one into wavelet
#halide_library("conv_3" SRCS "conv_3_generator.cpp")
#file(GLOB GENS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/*_generator.cpp")
#foreach(GEN_SRC ${GENS})
# string(REPLACE "_generator.cpp" "" GEN_NAME "${GEN_SRC}")
# halide_library("${GEN_NAME}" SRCS ${GEN_SRC})
# target_link_libraries(conv-3 "${GEN_NAME}" )
#endforeach()
#target_link_libraries(conv-3 PUBLIC "conv_3" pthread)
halide_generator(conv_3.generator SRCS conv_3_generator.cpp)
set(LIB conv_3)
halide_library_from_generator(${LIB} GENERATOR conv_3.generator)
target_link_libraries(conv-3 PRIVATE ${LIB} pthread)
make VERBOSE=1 results in
/usr/bin/c++ -rdynamic CMakeFiles/conv-3.dir/main.cpp.o -o conv-3 ./genfiles/conv_3/conv_3.a -lpthread ./genfiles/halide_rt_host/halide_rt_host.a -ldl
PS: Manually adding -lpthread to the end of the command results in resolution of the pthread linking error.
Do I need to change my CMake file?
Edit : Halide.cmake file can be found here
halide_library, halide_library_from_generator, halide_generator functions are defined in Halide.cmake
Edit 2
OS : Ubuntu 18.04.3 LTS
compiler : cc/c++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
linker : GNU ld (GNU Binutils for Ubuntu) 2.30
LLVM : LLVM version 8.0.0 Optimized build
LLVM options : none
Build target : binary
Please add details about:
- OS
- compiler/linker versions being used
- LLVM version being used, and whether it is a binary or built locally
- LLVM options being used
There were two ways in which this problem was solved:
Manually appending -lpthread -lHalide to
/usr/bin/c++ -rdynamic CMakeFiles/conv-3.dir/main.cpp.o -o conv-3 ./genfiles/conv_3/conv_3.a -lpthread ./genfiles/halide_rt_host/halide_rt_host.a -ldl
This solved the linking problem
setting CXX compiler to clang++-8

CMake: Linking error when using add_library with many sources and using it in target_link_libraries

Full listing included at the end, here specific parts:
add_library(common common.h utils.h utils.cc)
and
add_executable(type_test type_test.cc)
target_link_libraries(type_test
${GTEST_BOTH_LIBRARIES}
ast
common
compilation_context
easyloggingpp
functions
lexer
parser
${CMAKE_THREAD_LIBS_INIT})
add_test(type_test COMMAND out/type_test)
Now when I run cmake . --GNinja and later ninja type_test, I get:
[0/1] Re-running CMake...
-- Found LLVM 6.0.1
-- Using LLVMConfig.cmake in: /usr/lib/llvm-6.0/cmake
-- Configuring done
-- Generating done
-- Build files have been written to: /home/gru/Code/schwifty
[1/1] Linking CXX executable out/type_test
FAILED: out/type_test
: && /usr/bin/clang++ -DELPP_FEATURE_CRASH_LOG CMakeFiles/type_test.dir/type_test.cc.o -o out/type_test /usr/local/lib/libgtest.a /usr/local/lib/libgtest_main.a out/libast.a out/libcommon.a out/libcompilation_context.a out/libeasyloggingpp.a out/libfunctions.a out/liblexer.a out/libparser.a -lpthread && :
/usr/bin/ld: out/libcompilation_context.a(type.cc.o): in function `schwifty::Types::parse_type_string_internal(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
type.cc:(.text+0x18cb): undefined reference to `schwifty::utils::startswith(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: type.cc:(.text+0x1c04): undefined reference to `schwifty::utils::startswith(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
schwifty::utils::startswith is definitely declared in utils.h and implemented in utils.cc.
Full listing available here:
cmake_minimum_required(VERSION 3.10)
project(schwifty)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DELPP_FEATURE_CRASH_LOG")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out)
find_package(PythonInterp 3.6 REQUIRED)
file(MAKE_DIRECTORY downloads external)
#
# Easylogging++
#
if (EXISTS "external/easyloggingpp")
else ()
file(MAKE_DIRECTORY external/easyloggingpp)
file(DOWNLOAD https://github.com/muflihun/easyloggingpp/archive/v9.96.4.zip
downloads/easyloggingpp.zip)
execute_process(COMMAND unzip downloads/easyloggingpp.zip -d downloads)
file(GLOB easyloggingpp_files
downloads/easyloggingpp-9.96.4/src/easylogging++.*)
file(COPY ${easyloggingpp_files} DESTINATION external/easyloggingpp)
endif ()
include_directories(external/easyloggingpp)
add_library(easyloggingpp external/easyloggingpp/easylogging++.cc)
#
# Local lib targets
#
add_library(ast ast.h ast.cc)
add_library(ast_compare_visitor ast_compare_visitor.h ast_compare_visitor.cc)
add_library(classes classes.h classes.cc)
add_library(codegen
codegen.h
codegen.cc
codegen_common.h
codegen_common.cc
expression_type_visitor.cc
expression_type_visitor.h)
add_library(common common.h utils.h utils.cc)
add_library(compilation_context
compilation_context.h
compilation_context.cc
enum.h
enum.cc
errors.h
errors.cc
operators.h
operators.cc
type.h
type.cc)
add_library(functions functions.h functions.cc)
add_library(jit jit.cc jit.h)
add_library(lexer lexer.cc lexer.h lexer_common.cc lexer_common.h)
add_library(parser parser.h parser.cc)
add_library(runtime runtime.cc runtime.h)
add_library(type_inference
type_inference.h
type_inference.cc
symbol_visitor.cc
symbol_visitor.h
type_inference_visitor.cc
type_inference_visitor.h)
#
# External lib targets
#
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs all)
find_package(FMT REQUIRED CONFIG)
#
# Schwifty main executable
#
add_executable(schwifty schwifty.cc)
target_link_libraries(schwifty
${llvm_libs}
ast
classes
codegen
common
compilation_context
easyloggingpp
fmt::fmt
functions
lexer
parser
runtime
type_inference)
#
# Testing
#
enable_testing()
find_package(GTest REQUIRED)
find_package(Threads)
include_directories(${GTEST_INCLUDE_DIRS})
add_executable(codegen_test codegen_test.cc)
target_link_libraries(codegen_test
${GTEST_BOTH_LIBRARIES}
${llvm_libs}
easyloggingpp
ast
classes
codegen
common
compilation_context
fmt::fmt
functions
jit
lexer
parser
runtime
type_inference
${CMAKE_THREAD_LIBS_INIT})
add_test(codegen_test COMMAND out/codegen_test)
add_executable(lexer_test lexer_test.cc)
target_link_libraries(lexer_test
${GTEST_BOTH_LIBRARIES}
ast
common
compilation_context
easyloggingpp
functions
lexer
parser
fmt::fmt
${CMAKE_THREAD_LIBS_INIT})
add_test(lexer_test COMMAND out/lexer_test)
add_executable(parser_test parser_test.cc)
target_link_libraries(parser_test
${GTEST_BOTH_LIBRARIES}
ast
ast_compare_visitor
compilation_context
common
easyloggingpp
functions
lexer
parser
fmt::fmt
${CMAKE_THREAD_LIBS_INIT})
add_test(parser_test COMMAND out/parser_test)
add_executable(type_test type_test.cc)
target_link_libraries(type_test
${GTEST_BOTH_LIBRARIES}
ast
common
compilation_context
easyloggingpp
functions
lexer
parser
${CMAKE_THREAD_LIBS_INIT})
add_test(type_test COMMAND out/type_test)
add_executable(type_inference_test type_inference_test.cc)
target_link_libraries(type_inference_test
${GTEST_BOTH_LIBRARIES}
easyloggingpp
ast
classes
common
compilation_context
functions
fmt::fmt
lexer
parser
runtime
type_inference
${CMAKE_THREAD_LIBS_INIT})
add_test(type_inference_test COMMAND ./out/type_inference_test)
add_test(NAME end_to_end_tests
WORKING_DIRECTORY ${CTEST_SOURCE_DIRECTORY}
COMMAND ${PYTHON_EXECUTABLE} end_to_end_tests.py)
And all code available here: https://bitbucket.org/gruszczy/schwifty/src/default/
It seems like you're not following modern CMake best practices. Your libraries don't link to anything, only your executables do. When compiling by hand, this is how one would do it, because static libraries don't link to other static libraries, only executables do. In CMake however, the world works a bit different.
You should always link to libraries you use, and only what you directly use, not what you indirectly use. For both executable and library targets. The targets in CMake form a hierarchy of libraries and executables. CMake keeps track of what needs what and links accordingly. For example, if you executable exe requires library liba which itself requires library libb, you should NOT link your executable to both liba and libb, but instead link liba to libb and only link your executable to liba. CMake will do the rest and resolve the hierarchy to form a correct linking command.
Linking order matters for static libraries with bfd ld. (not sure about gold). libcommon.a is read, processed and dropped before libcompilation_context.a is brought around which needs symbols declared in libcommon.a.
The old fashion way to fix this was ld c.o -lcommon -lcompilation_context -lcommon. cmake's LINK_INTERFACE_MULTIPLICITY should (I think) solve your problem.