Skip to content

devos0024/cmake-swig

 
 

Repository files navigation

Build Status Build status

Introduction

This is a complete example of how to create a Modern CMake C++ Project with the SWIG code generator to generate wrapper and package for Python, .Net and Java.

This project should run on GNU/Linux, MacOS and Windows.

Wrapper/Package Status

Python 2 | Python 3 | .Net | Java
  • GNU/Linux wrapper
  • MacOS wrapper
  • Windows wrapper
  • GNU/Linux wrapper
  • MacOS wrapper
  • Windows wrapper
  • GNU/Linux wrapper
  • MacOS wrapper
  • Windows wrapper
  • GNU/Linux wrapper
  • MacOS wrapper
  • Windows wrapper

Dependencies

To complexify a little, the CMake project is composed of three libraries (Foo, Bar and FooBar) with the following dependencies:

Foo:
Bar:
FooBar: PUBLIC Foo PRIVATE Bar
FooBarApp: PRIVATE FooBar

Codemap

The project layout is as follow:

C++ Project Build

To build the C++ project, as usual:

cmake -S. -Bbuild
cmake --build build --target all

Managing RPATH

Since we want to use the CMAKE_BINARY_DIR to generate the wrapper package (e.g. python wheel package) as well as be able to test from the build directory. We need to enable:

set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)

And have a finely tailored rpath for each library.

For Foo and Bar which depend on nothing:

set(CMAKE_INSTALL_RPATH "$ORIGIN")

For FooBar which depend on Foo and Bar:

set(CMAKE_INSTALL_RPATH "$ORIGIN:$ORIGIN/../Foo:$ORIGIN/../Bar")

For FooBarApp which depend on FooBar:

set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/../FooBar")

SWIG Wrapper Generation

Using swig to generate wrapper it's easy thanks to the modern UseSWIG module (CMake >= 3.14).

Creating a Python binary package containing all .py and .so (with good rpath) is not so easy...

note: SWIG automatically put its target(s) in all, thus make will also call swig and generate _module.so.

Managing SWIG generated files

Since python use the directory name where __init__.py file is located.
We would like to have pyFoo.py generated file in build/Foo and not in build/Foo/python.
You can use CMAKE_SWIG_DIR to change the output directory for the .py file e.g.:

set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}/..)

And you can use CMAKE_LIBRARY_OUTPUT_DIRECTORY to change the output directory for the .so file e.g.:

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..)

[optional]You can use SWIG_OUTFILE_DIR to change the output directory for the .cxx file e.g.:

set(SWIG_OUTFILE_DIR ${CMAKE_CURRENT_BINARY_DIR}/..)

Then you only need to create a __init__.py file in build/Foo to be able to use the build directory to generate the Python package.

note: you allways need $ORIGIN/../${PROJECT_NAME}/.libs since _pyFoo.so will depend on libFoo.so (which will be built in the same directory see above).

Why setup.py has to be generated

To avoid to put hardcoded path to SWIG .so generated files, we could use $<TARGET_FILE_NAME:tgt> to retrieve the file (and also deal with Mac/Windows suffix, and target dependencies).
In order for setup.py to use cmake generator expression (e.g. $<TARGET_FILE_NAME:_pyFoo>). We need to generate it at build time (e.g. using add_custom_command()).
note: This will also add automatically a dependency between the command and the TARGET !

Testing Python

Testing using virtualenv

Testing using the CMAKE_BINARY_DIR

Contributing

The CONTRIBUTING.md file contains instructions on how to file the Contributor License Agreement before sending any pull requests (PRs). Of course, if you're new to the project, it's usually best to discuss any proposals and reach consensus before sending your first PR.

License

Apache 2. See the LICENSE file for details.

Disclaimer

This is not an official Google product, it is just code that happens to be owned by Google.

About

Modern CMake C++ SWIG Sample

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • CMake 40.3%
  • Dockerfile 32.7%
  • Makefile 15.5%
  • Shell 6.8%
  • C++ 4.5%
  • Python 0.2%