Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smart way to CMake a project using pybind11 by ExternalProject_Add

Tags:

cmake

pybind11

I'm writing a python module using pybind11 with CMake 3.9.4. As it is convenience, I wish to download pybind11 source files using ExternalProject_Add in my CMakeLists.txt.

When I run cmake ., it does not download pybind11 source files, and throws an error.

CMake Error at CMakeLists.txt:21 (add_subdirectory):
  The source directory
    /Users/me/foo/pybind11_external-prefix/src/pybind11_external
  does not contain a CMakeLists.txt file.

CMake Error at CMakeLists.txt:22 (pybind11_add_module):
  Unknown CMake command "pybind11_add_module".

There is a workaround:

  1. comment out the last 3 lines in CMakeLists.txt
  2. run cmake .
  3. run make (then, it downloads pybind11 source files)
  4. restore the last 3 lines in CMakeLists.txt
  5. run cmake .
  6. run make

However, this is not smart... Is there any way to download pybind11 using ExternalProject_Add without commenting the lines out and restoring them (and without running cmake and make twice)?

/Users/me/foo/CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
project(foo)
set(CMAKE_CXX_STANDARD 14)

include(ExternalProject)
ExternalProject_Add(
        pybind11_external
        GIT_REPOSITORY https://github.com/pybind/pybind11.git
        GIT_TAG v2.2.1
        CONFIGURE_COMMAND ""
        BUILD_COMMAND ""
        INSTALL_COMMAND ""
)
set(PYBIND11_CPP_STANDARD -std=c++14)
ExternalProject_Get_Property(pybind11_external source_dir)
include_directories(${source_dir}/include)

add_subdirectory(${source_dir})             # comment out, then restore this line
pybind11_add_module(foo SHARED foo.cpp)     # comment out, then restore this line
add_dependencies(foo pybind11_external)     # comment out, then restore this line

/Users/me/foo/foo.hpp

#ifndef FOO_LIBRARY_H
#define FOO_LIBRARY_H

#include<pybind11/pybind11.h>

int add(int i, int j);

#endif

/Users/me/foo/foo.cpp

#include "foo.hpp"

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin";
    m.def("add", &add, "A function which adds two numbers");
}
like image 666
Pengin Avatar asked Dec 11 '22 09:12

Pengin


1 Answers

With CMake's FetchContent module (version 3.11+), you can do this:

include(FetchContent)
FetchContent_Declare(
    pybind11
    GIT_REPOSITORY https://github.com/pybind/pybind11
    GIT_TAG        v2.2.3
)

FetchContent_GetProperties(pybind11)
if(NOT pybind11_POPULATED)
    FetchContent_Populate(pybind11)
    add_subdirectory(${pybind11_SOURCE_DIR} ${pybind11_BINARY_DIR})
endif()

This will download pybind11 at configure time, and add_subdirectory it. Then you're ready to call pybind11_add_module.

like image 152
CharlesB Avatar answered Mar 29 '23 23:03

CharlesB