CMake won't Link C library to C++ program
Asked Answered
V

1

15

Probably the shortest working example I can think of:

CMakeLists.txt:

project(myprogs)
cmake_minimum_required(VERSION 2.8)

add_executable(myprog2 main.c)
add_executable(myprog main.cpp)
add_library(mylib SHARED mylib.c)

target_link_libraries(myprog2 mylib)
target_link_libraries(myprog mylib)

main.c/main.cpp (identical contents):

#include "mylib.h"

int main(int argc, char** argv)
{
  doit();
}

mylib.h:

#ifndef MYLIB_H
#define MYLIB_H

void doit(void);

#endif

mylib.c:

#include "mylib.h"
#include <stdio.h>

void doit(void)
{
  printf("doit");
}

System:

  • Ubunto 15.10
  • gcc 5.2.1/clang 3.6.2 (tried both)
  • CMake 3.2.2

When I do a make myprog, myprog's link phase complains that there is an undefined reference to doit. However, if I use make myprog2, everything links correctly and the program runs as expected.

I don't understand why CMake isn't properly linking to mylib correctly in the C++ program. Getting verbose output form the compiler gives (I've trimmed some of the linking to system library paths/object files):

"/usr/bin/ld" -export-dynamic --eh-frame-hdr -m elf_x86_64 -dyna mic-linker /lib64/ld-linux-x86-64.so.2 -o myprog CMakeFiles/myprog.dir/main.cpp.o libmylib.so -rpath /home/andrew/code/misc/myprog/build -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc

Strangely, it's not using a -lmylib to link with mylib. I get a similar output for myprog2.

My question is why is this happening, and more importantly, how do I get myprog to properly link to mylib?

Vierno answered 22/12, 2015 at 3:43 Comment(1)
It is not CMake that has the problem, but rather the linker. CMake does not do the linkingCacilia
M
38

You need to declare functions with extern "C" in c++. The compiler changes function names in order to allow function overloading, so for instance

int function(int value);

and

int function(char *value);

both can be defined in with exactly the same name, the compiler will generate two different functions with different names for this to work correctly.

In you can't do this, and the function name will not need to be modified. By using extern "C" you prevent the compiler from altering function names, and so the link phase will work as you expect it.

To fix it, start main.cpp this way:

extern "C" {
#include "mylib.h"
}
Melodimelodia answered 22/12, 2015 at 3:45 Comment(7)
hmm... this makes sense, but why don't I have to wrap system C libraries with extern "C" (or should I be and have been lucky so far?) For example, I searched the GTK+3.0 headers and there's not a single mention of extern "C" and I'm not doing this wrapping in my C++ codes.Vierno
@Vierno - it's because most include files already contain lines like #ifdef __cplusplus, extern "C" { and #endif.Zhukov
Are you using GTK-3.0 in c++ code? Or is it gtkmm-3.0?Melodimelodia
It is not gtkmm-3.0, but GTK-3.0 (yeah, I probably should use gtkmm, but in the past I've run into problems where gtkmm lags behind feature-wise from gtk+)Vierno
@Zhukov As I said, I did a grep search of all the GTK+ headers and didn't find a single mention of extern "C" at all. I don't know where else the extern "C" could be hiding.Vierno
I just confirmed what you say and there are extern "C"'s, It's a macro called G_BEGIN_DECLS defiend in /usr/include/glib-2.0/glib/gmacros.h which is simply extern "C" {, and of course has to be matched with a corresponding G_END_DECLS.Melodimelodia
Hallelujah! This solved my problem after an hour of Googling!Frequentative

© 2022 - 2024 — McMap. All rights reserved.