0

File structure under folder /home/cyan/proj

fst
 | -- include
 |     |-- fstlib
 |            |-- fst_row_reader.h
 |            |-- fst
 |                 |-- interface
 |                         |-- fststore.h
 |
 | -- lib
       |-- libfst.so

test.cc

CMakeLists.txt

fst folder is a library I added and used in test.cc.

test.cc

#include <iostream>
#include <fstlib/fst_row_reader.h>

class Add{
public:
    double add2num(int a, double b){
        return a + b;
    }
};

extern "C"
{
    Add* test_new(){
        return new Add;
    }
    int my_func(Add* t, int a, double b){
        return t->add2num(a, b);
    }
}

*Note: In my actual test.cc I used some functions in fst library. Here is just a sample for simplicity.

Problem

Previously, I can simply use g++ test.cc -fPIC -shared -o test.so to get the .so file. However, since I included the fst lib, I got the following error:

In file included from /home/cyan/proj/fst/include/fstlib/fst_row_reader.h:7:0,
                 from read_fst.cc:1:
/home/cyan/proj/fst/include/fstlib/fst_reader.h:6:10: fatal error: fstlib/fst/interface/fststore.h: No such file or directory
 #include <fstlib/fst/interface/fststore.h>
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

My attempt:

$ g++ -L/home/cyan/proj/fst/lib -l:libfst.so

/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
---------------------------------------------------------
$ g++ read_fst.cc -L /home/cyan/proj/fst/lib/libfst.so -fPIC -shared -o test.so 

In file included from /home/cyan/proj/fst/include/fstlib/fst_row_reader.h:7:0,
                 from read_fst.cc:1:
/home/cyan/proj/fst/include/fstlib/fst_reader.h:6:10: fatal error: fstlib/fst/interface/fststore.h: No such file or directory
 #include <fstlib/fst/interface/fststore.h>
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

I also tried CMakeLists.txt to link the fst library as well as create a .so file under the path /home/cyan/proj/build/lib. But I am very new to CMake. Here is my attempt:

cmake_minimum_required(VERSION 3.0.0)
project(MY_PROJ VERSION 0.1.0)
set(mylibSRCS test.cc)
message(STATUS "Build test.so")
include_directories(${CMAKE_SOURCE_DIR}/fst/include)
link_directories(${CMAKE_SOURCE_DIR}/fst/lib)
add_library(MY_PROJ SHARED ${mylibSRCS})
set_target_properties(MY_PROJ PROPERTIES
            LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
target_link_libraries(MY_PROJ ${CMAKE_SOURCE_DIR}/fst/lib/libfst.so)  # link to my fst lib
target_link_libraries(MY_PROJ)

But I can't find any files under the /home/cyan/proj/build/lib. I guess this is my CMake command issue. Could you please help me with this problem?

Cyan
  • 319
  • 2
  • 8
  • You create a variable `LIBRARY_OUTPUT_PATH` which has no special meaning for CMake. Correct name of variable which controls output directory of the shared library is `CMAKE_LIBRARY_OUTPUT_DIRECTORY`. See that answer: https://stackoverflow.com/a/3744130/3440745. – Tsyvarev Mar 23 '22 at 18:53
  • @Tsyvarev thx for answering. I tried. Unfortunately I still couldn't find any files under the path – Cyan Mar 23 '22 at 18:57
  • Setting property `LIBRARY_OUTPUT_DIRECTORY` works for me. You could print value of variable `PROJECT_BINARY_DIR` to be sure it points to the expected directory (`/home/cyan/proj/build`): `message(STATUS "PROJECT_BINARY_DIR: ${PROJECT_BINARY_DIR}")`. – Tsyvarev Mar 23 '22 at 19:25

1 Answers1

1

The most convenient way of using a library located on the file system imho associating the info with a imported library target which allows you to just link it using target_link_libraries:

add_library(fst SHARED IMPORTED)
target_include_directories(fst INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/fst/include)
set_target_properties(fst PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/fst/lib/libfst.so)

...

target_link_libraries(MY_PROJ PRIVATE fst)

this way the info is easy to reuse and it listed in a single place instead of spreading it into different target properties of the linking target.

A bit more advanced, but even better would be to write fst-config.cmake and fst-config-version.cmake files and putting them in the "installation directory" of the library which would allow you to use find_package(fst) to execute the logic creating the imported library which makes the library simple to reuse across multiple cmake projects, but this is beyond the scope of this answer. The find_package documentation provides more info about how to do this.


Btw: Note the use of CMAKE_CURRENT_SOURCE_DIR instead of CMAKE_SOURCE_DIR. If you're specifying absolute paths inside the directory containing the CMakeLists.txt file containing the variable reference, since CMAKE_SOURCE_DIR refers to the toplevel source dir which may be different, if you're including the CMakeLists.txt using add_subdirectory.

fabian
  • 80,457
  • 12
  • 86
  • 114
  • Thanks. I tried to generate a static lib instead of a shared lib then it works. The reason for failing to get shared lib is irrelevant to this question, so this problem can be regarded as solved. The last thing is I can only use `include_directories` instead of `target_include_directories`, which is supposed to be a scaling issue. Thanks again! – Cyan Mar 23 '22 at 19:58
  • @Cyan any references to why `target_include_directories` is supposed to be a scaling issue? As long as your library targets link your other library targets "as private as possible", there shouldn't be too many include dirs for the compiler to consider and adding the info at directory scope could result in the include directories accidentally being added to targets should another target be created in the `CMakeLists.txt` or one added via `add_subdirectory`... – fabian Mar 23 '22 at 20:12
  • for my case `target_include_directories ` generates a config error: `Cannot specify include directories for imported target "fst"`, but `include_directories` works, which I don't quite understand – Cyan Mar 23 '22 at 20:22
  • Oh, right... That requires cmake >= 3.11... Probably setting the `INTERFACE_INCLUDE_DIRECTORIES` target property does the trick for older cmake versions... – fabian Mar 23 '22 at 20:46