0

I am trying to build the library https://github.com/sdwfrost/liblsoda using CMake. Specifically, the directory structure is the following:

.
├── CMakeLists.txt
├── main.cpp
└── src
    ├── blas.h
    ├── cfode.c
    ├── cfode_static.c
    ├── cfode_static.inc
    ├── CMakeLists.txt
    ├── common.c
    ├── common.h
    ├── corfailure.c
    ├── correction.c
    ├── daxpy.c
    ├── ddot.c
    ├── dgefa.c
    ├── dgesl.c
    ├── dscal.c
    ├── ewset.c
    ├── fnorm.c
    ├── idamax.c
    ├── intdy.c
    ├── lsoda.c
    ├── lsoda.h
    ├── lsoda_internal.h
    ├── Makefile
    ├── methodswitch.c
    ├── orderswitch.c
    ├── printcf.c
    ├── prja.c
    ├── scaleh.c
    ├── solsy.c
    ├── stoda.c
    ├── strdup_printf.c
    └── vmnorm.c

and the contents of the CMakeLists.txt in the src directory is:

set(TARGET lsodaC)

set(SRC
    ${CMAKE_CURRENT_SOURCE_DIR}/cfode.c
    ${CMAKE_CURRENT_SOURCE_DIR}/cfode_static.c
    ${CMAKE_CURRENT_SOURCE_DIR}/common.c
    ${CMAKE_CURRENT_SOURCE_DIR}/corfailure.c
    ${CMAKE_CURRENT_SOURCE_DIR}/correction.c
    ${CMAKE_CURRENT_SOURCE_DIR}/daxpy.c
    ${CMAKE_CURRENT_SOURCE_DIR}/ddot.c
    ${CMAKE_CURRENT_SOURCE_DIR}/dgefa.c
    ${CMAKE_CURRENT_SOURCE_DIR}/dgesl.c
    ${CMAKE_CURRENT_SOURCE_DIR}/dscal.c
    ${CMAKE_CURRENT_SOURCE_DIR}/fnorm.c
    ${CMAKE_CURRENT_SOURCE_DIR}/idamax.c
    ${CMAKE_CURRENT_SOURCE_DIR}/intdy.c
    ${CMAKE_CURRENT_SOURCE_DIR}/lsoda.c
    ${CMAKE_CURRENT_SOURCE_DIR}/methodswitch.c
    ${CMAKE_CURRENT_SOURCE_DIR}/orderswitch.c
    ${CMAKE_CURRENT_SOURCE_DIR}/prja.c
    ${CMAKE_CURRENT_SOURCE_DIR}/scaleh.c
    ${CMAKE_CURRENT_SOURCE_DIR}/solsy.c
    ${CMAKE_CURRENT_SOURCE_DIR}/stoda.c
    ${CMAKE_CURRENT_SOURCE_DIR}/vmnorm.c
    ${CMAKE_CURRENT_SOURCE_DIR}/strdup_printf.c
)

add_library(${TARGET} SHARED ${SRC})
set_target_properties(${TARGET} PROPERTIES LINKER_LANGUAGE CXX)
# SET(CMAKE_C_LINK_EXECUTABLE ${CMAKE_CXX_LINK_EXECUTABLE})
set_property(TARGET ${TARGET} PROPERTY POSITION_INDEPENDENT_CODE ON)

target_include_directories(${TARGET}
    PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)

target_link_directories(${TARGET}
    PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)

Furthermore, the main.cpp is the following (taken from the test directory of the above repo):

/**
 *
 */
#include <iostream>
#include "common.h"
#include "lsoda.h"

int fex(double t, double *y, double *ydot, void *data)
{
    ydot[0] = 1.0E4 * y[1] * y[2] - .04E0 * y[0];
    ydot[2] = 3.0E7 * y[1] * y[1];
    ydot[1] = -1.0 * (ydot[0] + ydot[2]);
    return(0);
}

int test(void)
{
    double          atol[3], rtol[3], t, tout, y[3];
    int             neq = 3;
    int             iout;

    y[0] = 1.0E0;
    y[1] = 0.0E0;
    y[2] = 0.0E0;
    t = 0.0E0;
    tout = 0.4E0;
    struct lsoda_opt_t opt = {0};
    opt.ixpr = 0;
    opt.rtol = rtol;
    opt.atol = atol;
    opt.itask = 1;

    rtol[0] = rtol[2] = 1.0E-4;
    rtol[1] = 1.0E-4;
    atol[0] = 1.0E-6;
    atol[1] = 1.0E-10;
    atol[2] = 1.0E-6;


    struct lsoda_context_t ctx;
    ctx.function = fex;
    ctx.neq = neq;
    ctx.data = nullptr;
    ctx.state = 1;

    lsoda_prepare(&ctx, &opt);

    for (iout = 1; iout <= 12; iout++) {
        lsoda(&ctx, y, &t, tout);
        printf(" at t= %12.4e y= %14.6e %14.6e %14.6e\n", t, y[0], y[1], y[2]);
        if (ctx.state <= 0) {
            printf("error istate = %d\n", ctx.state);
            exit(0);
        }
        tout = tout * 10.0E0;
    }
    lsoda_free(&ctx);
    return(0);
}


int main(int argc, char **argv) {
    test();
    return 0;
}

Finally, the root-most CMakeLists.txt has the following contents:

cmake_minimum_required(VERSION 3.14)

project(sample_mwe)

set(CMAKE_CXX_FLAGS "-O3")

add_executable(main main.cpp)

add_subdirectory(src)

target_link_libraries(main
        PUBLIC lsodaC
)

The question is, when executing

mkdir build
cd build
cmake ..
make main

I am getting

[  4%] Building C object src/CMakeFiles/lsodaC.dir/cfode.c.o
[  8%] Building C object src/CMakeFiles/lsodaC.dir/cfode_static.c.o
[ 12%] Building C object src/CMakeFiles/lsodaC.dir/common.c.o
[ 16%] Building C object src/CMakeFiles/lsodaC.dir/corfailure.c.o
[ 20%] Building C object src/CMakeFiles/lsodaC.dir/correction.c.o
[ 24%] Building C object src/CMakeFiles/lsodaC.dir/daxpy.c.o
[ 28%] Building C object src/CMakeFiles/lsodaC.dir/ddot.c.o
[ 32%] Building C object src/CMakeFiles/lsodaC.dir/dgefa.c.o
[ 36%] Building C object src/CMakeFiles/lsodaC.dir/dgesl.c.o
[ 40%] Building C object src/CMakeFiles/lsodaC.dir/dscal.c.o
[ 44%] Building C object src/CMakeFiles/lsodaC.dir/fnorm.c.o
[ 48%] Building C object src/CMakeFiles/lsodaC.dir/idamax.c.o
[ 52%] Building C object src/CMakeFiles/lsodaC.dir/intdy.c.o
[ 56%] Building C object src/CMakeFiles/lsodaC.dir/lsoda.c.o
[ 60%] Building C object src/CMakeFiles/lsodaC.dir/methodswitch.c.o
[ 64%] Building C object src/CMakeFiles/lsodaC.dir/orderswitch.c.o
[ 68%] Building C object src/CMakeFiles/lsodaC.dir/prja.c.o
[ 72%] Building C object src/CMakeFiles/lsodaC.dir/scaleh.c.o
[ 76%] Building C object src/CMakeFiles/lsodaC.dir/solsy.c.o
[ 80%] Building C object src/CMakeFiles/lsodaC.dir/stoda.c.o
[ 84%] Building C object src/CMakeFiles/lsodaC.dir/vmnorm.c.o
[ 88%] Building C object src/CMakeFiles/lsodaC.dir/strdup_printf.c.o
[ 92%] Linking CXX shared library liblsodaC.so
[ 92%] Built target lsodaC
[ 96%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[100%] Linking CXX executable main
/usr/bin/ld: CMakeFiles/main.dir/main.cpp.o: in function `test()':
main.cpp:(.text+0x185): undefined reference to `lsoda_prepare(lsoda_context_t*, lsoda_opt_t*)'
/usr/bin/ld: main.cpp:(.text+0x1ac): undefined reference to `lsoda(lsoda_context_t*, double*, double*, double)'
/usr/bin/ld: main.cpp:(.text+0x1fd): undefined reference to `lsoda_free(lsoda_context_t*)'
collect2: error: ld returned 1 exit status
make[3]: *** [CMakeFiles/main.dir/build.make:98: main] Error 1
make[2]: *** [CMakeFiles/Makefile2:100: CMakeFiles/main.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:107: CMakeFiles/main.dir/rule] Error 2
make: *** [Makefile:124: main] Error 2

The question is why. I am building the C-portion src as a library, right, why won't it work the "usual" way?

Ilonpilaaja
  • 1,057
  • 1
  • 11
  • 21
  • 1
    When use C function in C++ code, you need to wrap with `extern "C"` either the function declaration in the header or the `#include` directive. BTW, with when create a library from mixed (C++ and C) sources, CMake automatically choose C++ linker. So `set_target_properties(${TARGET} PROPERTIES LINKER_LANGUAGE CXX)` is not needed. – Tsyvarev Jun 13 '21 at 16:24

0 Answers0