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:
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
?
If the C++ compiler provides its own versions of the C headers, the versions of those headers used by the C compiler must be compatible. Oracle Developer Studio C and C++ compilers use compatible headers, and use the same C runtime library. They are fully compatible.
In the C/C++ ecosystem, the best tool for project configuration is CMake. CMake allows you to specify the build of a project, in files named CMakeLists. txt, with a simple syntax (much simpler than writing Makefiles).
Both C++ CMake tools for Windows and Linux Development with C++ are required for cross-platform CMake development.
You need to declare c functions with extern "C"
in c++. The c++ 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 c++ with exactly the same name, the compiler will generate two different functions with different names for this to work correctly.
In c 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"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With