serizba / cppflow

Run TensorFlow models in C++ without installation and without Bazel
https://serizba.github.io/cppflow/
MIT License
788 stars 178 forks source link

Add modern cmake #124

Closed fferflo closed 2 years ago

fferflo commented 3 years ago

This adds support for building and installing this package with cmake, so that it can be used from other packages with a simple cmake interface and without having to copy headers:

An example out-of-source build would look like this:

git clone https://github.com/serizba/cppflow
cd cppflow
mkdir build
cd build
cmake -DBUILD_EXAMPLES=ON ..
make -j8

# Test run one of the examples
./examples/multi_input_output/multi_input_output

# This installs c++ code and cmake interface to system directories and enables other packages to find cppflow via 'find_package(cppflow)'
make install 
serizba commented 3 years ago

Hi @fferflo

Thanks for your time. This looks interesting. I will take a look as soon as I have time.

Thanks!

Gonzalo-Mier commented 2 years ago

I've look at this pull request and I would love to use it on my code. @serizba, could you look at it again, please?

ghost commented 2 years ago

I need this in my code as well, this is the way libraries should be used.

serizba commented 2 years ago

Hi @fferflo @Gonzalo-Mier @mkazharov !

Sorry for not doing this before. I have little experience with CMake, and I didn't give this much attention. But I see that people are looking forward to this addition.

I have two doubts (arising from my lack of experience with CMake):

Could the examples CMake be changed into standalone CMakes? Or what do you guys think about this?

I think some people use this library as a pattern for interacting with TensorFlow C API. So they clone it, modify it to their needs and then use they modified version. For this reason I like to have a flexible installation that does not require to globally install CppFlow once. That's why I pointed this two doubts.

Anyway, I really like your changes, and I think they are a good addition to the library.

ljn917 commented 2 years ago

@serizba In my opinion, the proposed cmake in this pr is better, because it makes unit testing much easier. In addition, other cmake project can just include this project.

To answer your questions

serizba commented 2 years ago

Thanks for your explanation @ljn917!

For the first point. If I have the TF C API in a specific folder, then how can I specify the value of tensorflow_INCLUDE_DIRS? Something like -Dtensorflow_INCLUDE_DIRS=/home/...? Or should I change the Findtensorflow.cmake adding a HINTS?

For the second point I think the best way is to change the CMake of the examples to the one in this PR (to keep the PR code). For the standalone CMake I can include it in the docs, showing how to run the examples.

How would a proper CMakeLists.txt for the examples look then?

Sorry for my lack of experience with CMake :)

Gonzalo-Mier commented 2 years ago

Hi @serizba, Thanks for considering this PR. I'm only answering to the second question, because I do not install the library due to its small size (I download and compile it together with my project when need it). I learnt how to use cmake efficiently recently from this tutorial: https://cliutils.gitlab.io/modern-cmake/

I created a cmake using the one in this PR as template. I removed examples and documentation information as I don't want to continuously compile them, and added support for FetchContent.

Doing these changes, I can add my version of CPPFlow to my personal projects as:

cmake_minimum_required(VERSION 3.14)
project(MyExample VERSION 1.0 LANGUAGES CXX)

FetchContent_Declare(cppflow
  URL https://github.com/Fields2Cover-group/cppflow/archive/refs/heads/master.zip
)
FetchContent_MakeAvailable(cppflow)

add_executable(MyExample simple_example.cpp)
target_link_libraries(MyExample PUBLIC cppflow)

I know this is not the original way of using the PR, but I add it as another easy way to use the library without install it thanks to cmake. Feel free to take what you need from my fork and thank you for your amazing job.

ljn917 commented 2 years ago

@serizba I think -Dtensorflow_INCLUDE_DIRS=... should work, though I have not tested it. In addition, it may be better to accept the top dir of tensorflow c api as TENSORFLOW_C_API_DIR and then add the include and lib later in the cmake.

fferflo commented 2 years ago

For the first point. If I have the TF C API in a specific folder, then how can I specify the value of tensorflow_INCLUDE_DIRS?

The canonical cmake way is to add the root directory of tensorflow api to CMAKE_PREFIX_PATH (as environment variable or via -DCMAKE_PREFIX_PATH=...) if it's not installed in system directories. This enables find_package to find the library (by calling find_library) and include directory (by calling find_path) and automatically add them to the target cppflow.

serizba commented 2 years ago

Thanks for your help!

Still I don't know how to create a simple CMakeLists.txt for a simple example. If I install first the cppflow library, and now I want to work with in another project, and another directory. I can call find_package(cppflow REQUIRED), but how can I obtain the include dirs of cppflow?

I've tried to create a CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)

project(example)

add_executable(example main.cpp)

find_package(cppflow REQUIRED)

target_include_directories(
  example
  ??????????
)

target_link_libraries(
  example
  ??????????
)

I've tried with ${cppflow_INCLUDE_DIRS} and ${cppflow_LIBRARIES} but they don`t exist.

ljn917 commented 2 years ago

@serizba Can you try cppflow::cppflow in the place of ???????????

serizba commented 2 years ago

Thanks @ljn917, that works!

ghost commented 2 years ago

@serizba and the others, thanks a lot for your effort, sorry I couldn't contribute!

garricklw commented 2 years ago

This adds support for building and installing this package with cmake, so that it can be used from other packages with a simple cmake interface and without having to copy headers:

  • Add cmake interface so that the installed library can be used from other projects via find_package(cppflow) and target_link_libraries(new_target PUBLIC cppflow)
  • Simplify examples cmake code by using the new cmake interface
  • Build all examples unless -DBUILD_EXAMPLES=OFF is passed
  • Enable out-of-source build by fixing hard-coded paths

An example out-of-source build would look like this:

git clone https://github.com/serizba/cppflow
cd cppflow
mkdir build
cd build
cmake -DBUILD_EXAMPLES=ON ..
make -j8

# Test run one of the examples
./examples/multi_input_output/multi_input_output

# This installs c++ code and cmake interface to system directories and enables other packages to find cppflow via 'find_package(cppflow)'
make install 

It would help out a C++ newbie like myself if the docs were updated with these instructions. Going to the current install page: https://serizba.github.io/cppflow/installation.html it looks like it only has instructions to install Tensorflow C libraries

serizba commented 2 years ago

Hi @garricklw

You are completely right! I had in mind changing the docs, I will try to do it sooner, its definitely an issue for newbies.

Thanks!

serizba commented 2 years ago

Hi @garricklw

I updated the docs, thanks for pointing this!

garricklw commented 2 years ago

Thanks @serizba, I think that'll help out a lot for the next newbie who comes along. After running those steps everything is working great for me.