CoinCheung
CoinCheung

Reputation: 115

How could I generate runnable shared library with cmake

I have seens some answers, but most of them does not work for me. So I would like to make everything clear by adding a new question, my CMakeLists.txt is like this:

cmake_minimum_required(VERSION 3.17)
project(example)

include_directories(./)
link_directories(./)

if (CMAKE_COMPILER_IS_GNUCXX)
    set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Os -g ${CMAKE_CXX_FLAGS}")
    message("CMAKE_COMPILER_IS_GNUCXX is True")
    message("option is: ${CMAKE_CXX_FLAGS}")
endif (CMAKE_COMPILER_IS_GNUCXX)




add_executable(main try.cpp)
target_link_libraries(main  fun)
set_property(TARGET main PROPERTY POSITION_INDEPENDENT_CODE 1 LINK_FLAGS -pie)

add_library(fun SHARED func.cpp)
# target_compile_options(fun PUBLIC "-pie")
target_link_libraries(fun PUBLIC "-pie")
set_property(TARGET fun PROPERTY POSITION_INDEPENDENT_CODE 1)

And the source code for try.cpp is:

#include<iostream>
#include "func.hpp"

int main() {
    using namespace std;
    cout << "hello from exe main" << endl;

    func();
    return 0;
}

The code for fun.cpp and fun.hpp is like this:

// func.hpp
void func();

// func.cpp
#include <iostream>

using std::cout;
using std::endl;

void func() {
    cout << "hell from so func\n";
}


int main() {
    cout << "hello from so main\n";
    return 0;
}

My problem is that: I got the following link error when I compile it with cmake:

Scanning dependencies of target fun
[ 25%] Building CXX object CMakeFiles/fun.dir/func.cpp.o
[ 50%] Linking CXX shared library libfun.so
[ 50%] Built target fun
Scanning dependencies of target main
[ 75%] Building CXX object CMakeFiles/main.dir/try.cpp.o
[100%] Linking CXX executable main
/usr/bin/ld: CMakeFiles/main.dir/try.cpp.o: in function `main':
/home/coin/learn-coding/projects/C/cmake/try.cpp:8: undefined reference to `func()'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/main.dir/build.make:105: main] Error 1
make[1]: *** [CMakeFiles/Makefile2:125: CMakeFiles/main.dir/all] Error 2
make: *** [Makefile:104: all] Error 2

What is the problem with the configuration and how could I make it work ?

By the way, I tried to compile with command line:

g++ -fPIC -pie  func.cpp -o libfun.so -shared
g++ try.cpp -o main -L. -lfun

Which does work when I run the generated main, but the generated so file cannot be runnable:

$ ./main
hello from exe main
hell from so func
$ ./libfun.so
Segmentation fault (core dumped)

What did I miss here ?

Upvotes: 0

Views: 1502

Answers (1)

KamilCuk
KamilCuk

Reputation: 140880

The following files based on this answer:

cat >CMakeLists.txt <<EOF
cmake_minimum_required(VERSION 3.17)
project(example)

if(CMAKE_COMPILER_IS_GNUCXX)
    add_compile_options(
        $<$<COMPILE_LANGUAGE:CXX>:-std=c++11>
        -Wall
        -Os
        -g
    )
endif()

add_executable(main try.cpp)
target_link_libraries(main PRIVATE fun)

add_library(fun SHARED func.cpp)
target_link_options(fun PRIVATE -Wl,-e,entry_point)


EOF

cat >func.cpp <<EOF
// func.hpp
void func();

// func.cpp
#include <iostream>

using std::cout;
using std::endl;

void func() {
    cout << "hell from so func\n";
}


static inline
int lib_main() {
    printf("hello from so main\n");
    return 0;
}

extern "C" const char interp_section[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";

extern "C" void entry_point()
{
    lib_main();
    exit(0);
}

EOF

cat >try.cpp <<EOF
#include<iostream>
void func();
int main() {
    using namespace std;
    cout << "hello from exe main" << endl;

    func();
    return 0;
}
EOF

when compiled with the following on my 64-bit system with glibc, it generates two files that are executable:

$ cmake -S . -B _build && cmake --build _build -- VERBOSE=1 
balbla compilation output
$ _build/main
hello from exe main
hell from so func
$ _build/libfun.so
hello from so main

I replaced std::cout with printf because I received a segmentation fault - I suspect global constructors are not beeing run and something in iostream destructors makes it go segfault.

I think adding LINK_FLAGS -pie) and target_link_libraries(fun PUBLIC "-pie") makes no point, it's handled with POSITION_INDEPENDENT_CODE property and I guess for shared library it's TRUE anyway (but I am not sure about that).

Upvotes: 2

Related Questions