Skip to content

Adding CMake support #7524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 55 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
318ecf0
Added CPM.cmake package manager and download_deps.cmake and utils
HerrNamenlos123 Mar 2, 2023
0719b68
Implemented CMake support for the core library
HerrNamenlos123 Mar 4, 2023
6022ad6
Add compile guards around source files
HerrNamenlos123 Mar 4, 2023
c052a86
CMake support for some addons and examples
HerrNamenlos123 Mar 5, 2023
b016972
Add CMake checks for dependencies on Linux
HerrNamenlos123 Mar 5, 2023
53ee56d
Improving CMake support with conscise examples and addons
HerrNamenlos123 Mar 15, 2023
1ebf023
Improve CMake comment
HerrNamenlos123 Mar 16, 2023
6b203c2
Merge branch 'openframeworks:master' into master
HerrNamenlos123 Mar 16, 2023
df337d1
Implement CMake scripts for Linux and fix a few preprocessor guards
HerrNamenlos123 Mar 16, 2023
94f0def
CMake: Add Android support
HerrNamenlos123 Apr 5, 2023
8cba920
CMake: Add Accelerometer and do not find OpenGL on Android
HerrNamenlos123 Apr 5, 2023
06a6169
ofxAccelerometer: Replace bzero with memset
HerrNamenlos123 Apr 5, 2023
b9ec3be
Add CMake support for Android
HerrNamenlos123 Apr 5, 2023
2b4ad2c
CMake: Add communication examples and network addon
HerrNamenlos123 Apr 5, 2023
9478731
Add CMake support for computer_vision examples
HerrNamenlos123 Apr 5, 2023
2f0a8f8
CMake: Implement Event examples
HerrNamenlos123 Apr 16, 2023
70fba6a
CMake: Add gl examples
HerrNamenlos123 Apr 16, 2023
99d179a
CMake: Implement graphics examples
HerrNamenlos123 Apr 16, 2023
6575066
CMake: Implement gui examples
HerrNamenlos123 Apr 16, 2023
d1e7363
CMake: Implement input_output examples
HerrNamenlos123 Apr 16, 2023
b499a9f
CMake: Implement rudimentary iOS examples, still need to be finalized…
HerrNamenlos123 Apr 16, 2023
1cdbb43
CMake: Implement math examples
HerrNamenlos123 Apr 16, 2023
8bc3b12
CMake: Implement shader examples
HerrNamenlos123 Apr 16, 2023
48630be
CMake: Implement sound examples
HerrNamenlos123 Apr 16, 2023
d1ad802
CMake: Implement string examples
HerrNamenlos123 Apr 16, 2023
867e937
CMake: Implement remaining examples
HerrNamenlos123 Apr 16, 2023
a00e0ac
CMake: Implement unit test support
HerrNamenlos123 Apr 19, 2023
ec0720f
Merge branch 'openframeworks:master' into master
HerrNamenlos123 Apr 19, 2023
57694d0
CMake: Fix dependencies on linux platforms
HerrNamenlos123 Apr 19, 2023
7f9408a
CMake: Remove examples and tests from ALL
HerrNamenlos123 Apr 19, 2023
7118c71
CMake: Add all_examples target
HerrNamenlos123 Apr 19, 2023
535d18a
CMake: Remove addons from ALL
HerrNamenlos123 Apr 19, 2023
f765ee3
CMake: Implement all_examples and tests on Linux
HerrNamenlos123 Apr 24, 2023
fcb8d12
gitignore: Ignore CLion cmake folders
HerrNamenlos123 Apr 24, 2023
8ba6d40
CMake: Switch to using CTest for unit tests
HerrNamenlos123 Apr 24, 2023
68e2e38
Fix import in ofAVFoundationVideoPlayer to build like before
HerrNamenlos123 Apr 24, 2023
806356d
Rename ofAVFoundationVideoPlayer to .mm for consistency and to allow …
HerrNamenlos123 Apr 24, 2023
c5c4fd5
Fix xcode to build ofAVFoundationVideoPlayer as objc++ instead of objc
HerrNamenlos123 Apr 24, 2023
3b96d25
CMake: Better errors and more documentation
HerrNamenlos123 Apr 24, 2023
4e92df8
Merge branch 'openframeworks:master' into master
HerrNamenlos123 Apr 24, 2023
9733957
CMake: Fix minor bug
HerrNamenlos123 Apr 24, 2023
3ceb9ed
Merge remote-tracking branch 'origin/master'
HerrNamenlos123 Apr 24, 2023
3ff399a
CMake: More documentation including images
HerrNamenlos123 Apr 24, 2023
d4a654b
CMake: Fix documentation
HerrNamenlos123 Apr 24, 2023
cbcd0af
CMake: Minor documentation tweaks
HerrNamenlos123 Apr 24, 2023
c285976
Merge branch 'openframeworks:master' into master
HerrNamenlos123 Apr 25, 2023
4e66b87
CMake: Implement assimp example changes
HerrNamenlos123 Apr 25, 2023
859798d
CMake: Add more documentation
HerrNamenlos123 Apr 25, 2023
c8aa476
Minor adjust gitignore
HerrNamenlos123 Apr 25, 2023
03c7789
Merge branch 'master' of https://github.com/HerrNamenlos123/openFrame…
HerrNamenlos123 Apr 25, 2023
26368dd
CMake: Work around another inconsistency on macos
HerrNamenlos123 Apr 25, 2023
96c7733
CMake: Fix linking for assimp3DModelLoaderExample
HerrNamenlos123 Apr 25, 2023
b84ad46
CMake: Improve Readme documentation
HerrNamenlos123 Jun 3, 2023
4532d60
Remove CPM.cmake and add first steps towards Conan support
HerrNamenlos123 Dec 20, 2023
82f7da6
CMake: Add more Conan packages
HerrNamenlos123 Dec 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ apps/*
# general
#########################

[Bb]uild/
[Bb]uild*/
[Oo]bj/
cmake-build-*/
*.o
examples/**/[Dd]ebug*/
examples/**/[Rr]elease*/
Expand Down
282 changes: 282 additions & 0 deletions CMAKE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@

# CMake Support

## Using CMake in your project

Setup steps for a completely new OF project:

- Create the following file structure:
![cmake-example-layout](assets/cmake-example-layout.png)
As you can see it is very concise.
- [CPM.cmake](https://github.com/cpm-cmake/CPM.cmake): Just [download the latest release](https://github.com/cpm-cmake/CPM.cmake/releases/latest) and place it in the cmake folder.
This is a 100% CMake-based package manager which allows us to easily add dependencies
- include/ and src/ files are taken from the [emptyExample](examples/templates/emptyExample/README.md)
- resources are optional
- .gitignore bare minimum:
```gitignore
[Bb]uild/
cmake-build-*/
```
- CMakeLists.txt:
```cmake
cmake_minimum_required(VERSION 3.16)
project(ofExample)

# Include CPM.cmake, a 100% CMake-based dependency manager (https://github.com/cpm-cmake/CPM.cmake)
include(cmake/CPM.cmake)

# CPMAddPackage("gh:openframeworks/openframeworks#v0.11.2") # Either the very short version (works for github/gitlab branches, tags and commit hashes)
CPMAddPackage("gh:HerrNamenlos123/openframeworks#master") # This line is to be removed from this example once the CMake support is merged into master
#CPMAddPackage("https://github.com/openframeworks/openFrameworks/archive/refs/tags/nightly.zip") # Or any URL or archive

# CPM automatically downloads and extract our dependencies, and calls add_subdirectory() for us.
# This is the fastest and easiest way to pull in modern C++ libraries with good, modern CMake support (especially true for C++17 header-only libraries).

set(SOURCE_FILES
src/main.cpp # Here, list all source files
src/ofApp.cpp
)

# In Visual Studio we must also add headers and resource files as sources, so they're listed in the IDE
if (MSVC)
file(GLOB_RECURSE HEADER_FILES include/**)
file(GLOB_RECURSE RESOURCE_FILES resources/**)
list(APPEND SOURCE_FILES ${HEADER_FILES} ${RESOURCE_FILES})
endif()

# The actual executable to build
add_executable(ofExample ${SOURCE_FILES})
source_group(TREE "${CMAKE_CURRENT_LIST_DIR}/" PREFIX "" FILES ${SOURCE_FILES}) # Group into Folders in VS

# C++ version of the project (independent from the version OF is built with)
target_compile_features(ofExample PUBLIC cxx_std_17)
set_target_properties(ofExample PROPERTIES CXX_EXTENSIONS OFF) # Disable non-standard compiler-specific extensions

# Include directories
target_include_directories(ofExample PUBLIC include)

# All Targets we depend upon, which pulls in all headers, definitions, libraries, ...
target_link_libraries(ofExample of::openframeworks of::ofxGui)

# Setting up paths correctly
set(BIN_DIR "${CMAKE_CURRENT_BINARY_DIR}/bin/$<IF:$<CONFIG:Debug>,debug,release>")
set_target_properties(ofExample PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${BIN_DIR}") # Where to place the compiled binary
set_target_properties(ofExample PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${BIN_DIR}") # Where to run from when debugging with F5 in VS
of_copy_runtime_to_bin_dir_after_build(ofExample "${BIN_DIR}") # Copy all shared libraries to the target location after building
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ofExample) # Set the VS startup project to run when pressing F5

# And potentially also copy any resource files to the target location
if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/resources")
add_custom_command(TARGET ofExample POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_LIST_DIR}/resources" "${BIN_DIR}/resources")
endif()
```

#### Additionally, you can use a precompiled header to speed up the compilation:
```cmake
target_precompile_headers(ofExample PRIVATE "include/pch.hpp")
```
And in `include/pch.hpp`:
```cpp
#ifndef PCH_HPP
#define PCH_HPP

#include "ofMain.h"
// And any other common header files that do not change frequently

#endif //PCH_HPP
```
Here you can add other headers like openFrameworks headers, standard library headers and third-party libraries that do not change frequently.

This has the effect that these libraries are 'precompiled', which is taking a long time once, but speeding up any subsequent build significantly.


#### And to build it: (Any compiler/toolchain)
```bash
mkdir build
cd build
cmake ..
cmake --build .
```

- For Visual Studio IDE, skip the last command and open the generated `ofExample.sln`
- For CLion and vscode, just open the root `CMakeLists.txt` in CLion or vscode with CMake extension, no terminal commands needed.

#### This results in:

An output directory including all resources and shared libraries it depends on, ready to be released. (see known issues)

![cmake-example-output](assets/cmake-example-output.png)

## Choosing the target platform

When not doing anything special, CMake will try to detect the target platform and then choose the correct binary package. However, in case it cannot determine it or if you want to choose a different target platform, this is how you can set it:

```bash
cmake .. -DOF_TARGET_ARCHITECTURE=<value>
```

Simply run the command with an arbitrary value and it will print an error message with all possible values.

## Visual Studio (and multi-config build systems)

`-j<number-of-cores>` has no effect in Visual Studio, it automatically uses all available cores.

In the following examples, we always use the command `cmake ..` in the build folder. However, you can also use following signature:
`cmake -S source_dir -B build_dir`. This way the current working directory is irrelevant and the two directories can be anywhere (especially useful for CI toolchains).

### Building inside the VS IDE

Open the generated `openFrameworks.sln` in your build folder with Visual Studio. Then, just build it like any other VS project. Right-click a project and click on `Set as Startup Project` to be able to run it with F5.

Remember not to change anything in the project setting, as it is overwritten by CMake. Every change must be done
in CMake to keep it cross-platform.

### Building VS project from the terminal

You can also build Visual Studio projects without actually opening Visual Studio, by the use of MSBuild. CMake does all of that for you.

Note that configurations in Visual Studio work a bit different compared to makefiles, as VS is a multi-configuration build tool, makefiles are not.

#### Build all examples
```bash
# either in root directory of openFrameworks, or setting -DBUILD_EXAMPLES=ON
mkdir build
cd build
cmake ..
cmake --build . --target=build_all_examples --config=Release # Or 'Debug'
```

#### Build specific example

Replace `ofNodeExample` with the project name of the example.

```bash
# either in root directory of openFrameworks, or setting -DBUILD_EXAMPLES=ON
mkdir build
cd build
cmake ..
cmake --build . --target=ofNodeExample --config=Release # Or 'Debug'
```

#### Run all tests

```bash
# either in root directory of openFrameworks, or setting -DBUILD_TESTS=ON
mkdir build
cd build
cmake ..
cmake --build . --config=Release # Or 'Debug'
ctest -C Release # Or 'Debug'
```

In the VS IDE, building RUN_TESTS (in CMakePredefinedTargets folder) does the same thing.

## Makefiles (and single-configuration build systems)

#### Building all examples

```bash
# either in root directory of openFrameworks, or setting -DBUILD_EXAMPLES=ON
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release # Or 'Debug'
cmake --build . --target=build_all_examples -j<number-of-cores>
```

#### Building specific example

```bash
# either in root directory of openFrameworks, or setting -DBUILD_EXAMPLES=ON
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release # Or 'Debug'
cmake --build . --target=ofNodeExample -j<number-of-cores>
```

#### Run all tests

```bash
# either in root directory of openFrameworks, or setting -DBUILD_TESTS=ON
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release # Or 'Debug'
cmake --build . -j<number-of-cores>
ctest -C Release # Or 'Debug'
```

## Jetbrains CLion

When starting with CLion, you do not generate anything with CMake. It's the opposite: You open your root CMakeLists.txt in CLion,
which then calls CMake for you.

CLion is especially useful when it comes to unit tests due to its excellent support for CMake CTest.

### CLion on Windows

Currently, MinGW/MSYS2 is entirely unsupported. If you want to use CLion on Windows, you must use the Microsoft MSVC toolchain
(Visual Studio), which is also faster and more reliable than MinGW or MSYS.
If [Visual Studio](https://visualstudio.microsoft.com/de/downloads/) is installed, it is automatically recognized in the CLion toolchain settings.
Thus, you can build using CLion's excellent IDE, while the Visual Studio compiler is used under the hood.
This results in the most robust development experience on Windows.

MinGW support is waiting to be implemented!

## Visual Studio Code

When working with Visual Studio Code, the default C++ extensions are recommended, as well as the CMake extension from Microsoft.
See the CLion section above, as the same applies to VS Code. The CMake extension simply invokes CMake, which then uses MSVC under the hood, just like CLion.

The CMake extension's panel in the left bar allows you to build and execute targets directly in VS Code.

# Known issues

- Currently, all shared libraries are always copied to the target location, even if they are not linked (including both debug and release versions)
- And only shared libraries from apothecary dependencies are copied, libraries from other dependencies are not

# Yet to be done

- [ ] Test everything on all Apple platforms
- [ ] Add full support for Android & iOS
- [ ] Add support for Emscripten
- [ ] Add support for MinGW/MSYS2
- [ ] Add CMake install targets, which would allow to:
- 1: Install the library globally, so that new OF projects can simply link to it instead of building from source.
- 2: Install projects derived from it into an installation directory, which in turn allows to:
- 3: Use CMake's CPack to bundle all installed files and create native installers for each platform. (e.g. .exe, .msi, .deb, .rpm, .dmg, etc.)

CMake has excellent support for cross-compilation for all of these platforms, one just needs a working dev environment
to test everything.

Feel free to contribute to make this list shorter, Happy Coding!

### Some hints for a future Android cross-compilation implementer:

> ```bash
> set(CMAKE_SYSTEM_NAME "Android")
> set(CMAKE_SYSTEM_VERSION 1)
>
> cmake .. -DCMAKE_C_COMPILER=x86_64-linux-android33-clang -DCMAKE_CXX_COMPILER=x86_64-linux-android33-clang++
>
> cmake .. \
> -DCMAKE_C_COMPILER=armv7a-linux-androideabi33-clang \
> -DCMAKE_CXX_COMPILER=armv7a-linux-androideabi33-clang++ \
> -DCMAKE_SYSTEM_NAME=Android \
> -DCMAKE_SYSTEM_VERSION=25
>
> cmake .. \
> -DCMAKE_SYSTEM_NAME=Android \
> -DCMAKE_SYSTEM_VERSION=25 \
> -DCMAKE_ANDROID_STANDALONE_TOOLCHAIN=/home/${USER}/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64
>
>
>
> https://developer.android.com/ndk/guides/cmake#command-line
>
> cmake .. -DCMAKE_TOOLCHAIN_FILE=/home/$USER/android-ndk-r25c/build/cmake/android.toolchain.cmake -DANDROID_ABI=x86_64
>
> AT LEAST CMake 3.19 !!! (better latest which is 3.26 at the time of writing)
>
> To update cmake:
> deb http://deb.debian.org/debian bullseye-backports main # put this into /etc/apt/sources.list
> sudo apt update && sudo apt install cmake -t bullseye-backports
> ```
92 changes: 92 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
cmake_minimum_required(VERSION 3.16)
project(openframeworks)

include(${CMAKE_CURRENT_LIST_DIR}/cmake/utils.cmake)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(OF_IS_MAIN_PROJECT ON)
else()
set(OF_IS_MAIN_PROJECT OFF)
endif()

# Here are all the options you can set for customizing your build
# BUILD_SHARED_LIBS can be set to build a dll
option(BUILD_EXAMPLES "Add all OpenFrameworks examples to the project" ${OF_IS_MAIN_PROJECT})
option(BUILD_TESTS "Add all OpenFrameworks examples to the project" ${OF_IS_MAIN_PROJECT})

# This defines the actual library
add_library(openframeworks)
add_library(of::openframeworks ALIAS openframeworks)

# This is another CMake script that adds the header locations and source files
include(${CMAKE_CURRENT_LIST_DIR}/libs/openFrameworks/CMakeLists.txt)

# find_package(unofficial-libtess2 CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED)
find_package(utf8cpp CONFIG REQUIRED)
find_package(FreeImage CONFIG REQUIRED)
find_package(uriparser CONFIG REQUIRED)
find_package(curl CONFIG REQUIRED)
find_package(freetype CONFIG REQUIRED)
find_package(pugixml CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(glew CONFIG REQUIRED)
find_package(glfw3 CONFIG REQUIRED)
find_package(cairo CONFIG REQUIRED)
find_package(libtess2 CONFIG REQUIRED)

target_link_libraries(openframeworks PUBLIC
glm::glm
utf8cpp
freeimage::freeimage
uriparser::uriparser
CURL::libcurl
Freetype::Freetype
pugixml::pugixml
nlohmann_json::nlohmann_json
GLEW::GLEW
glfw
cairo::cairo
libtess2::libtess2
)
message(STATUS "glm_INCLUDE_DIRS_RELEASE: ${glm_INCLUDE_DIRS_RELEASE}")
target_include_directories(openframeworks PUBLIC ${glm_INCLUDE_DIRS_RELEASE})

# C++ standard version and disabling non-standard compiler specific features
target_compile_features(openframeworks PUBLIC cxx_std_17)
set_target_properties(openframeworks PROPERTIES CXX_EXTENSIONS OFF)
set_target_properties(openframeworks PROPERTIES FOLDER "openframeworks")

# Preprocessor defines
target_compile_definitions(openframeworks PUBLIC
OF_USING_STD_FS # Use the new C++17 filesystem library instead of boost
UNICODE # WinAPI setup
_UNICODE
)

# Compiler flags specific to MSVC
if(MSVC)
target_compile_options(openframeworks PUBLIC "/Zc:__cplusplus") # Force MSVC to set __cplusplus macro correctly
target_compile_options(openframeworks PUBLIC "/MP") # Enable multi-core compilation
# target_link_options(openframeworks PUBLIC "/ignore:4099") # Suppress compiler warning that no .pdb file is available for debugging (in third-party libraries)
# target_link_options(openframeworks PUBLIC "/NODEFAULTLIB:LIBCMT") # Don't link to the default C runtime library (Conflicting with third-party libraries)
# target_link_options(openframeworks PUBLIC "/NODEFAULTLIB:$<IF:$<CONFIG:Debug>,MSVCRT,MSVCRTd>") # Don't link to the default C++ standard library (Conflicting with third-party libraries)
endif()

# Where compiled binaries should be placed
set_target_properties(openframeworks PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib/$<IF:$<CONFIG:Debug>,debug,release>"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib/$<IF:$<CONFIG:Debug>,debug,release>"
)

add_subdirectory(addons)

if (BUILD_EXAMPLES)
add_subdirectory(examples)
endif()

if (BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ if you have bugs or feature requests, consider opening an issue. If you are a d

We also have a developer's mailing list, which is useful for discussing issues around the development and future of OF.

## Working with CMake

CMake support is a new feature, which allows to build openFrameworks out of the box. It also allows CLion to be used as an IDE.
There is an entire page dedicated to [CMake support](CMAKE.md).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can say instead "CMake support is a new addition to openFrameworks. There is an entire page dedicated to CMake support.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a change, better?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great thanks!! 👍

## Developers

To grab a copy of openFrameworks for your platform, check the [download page](http://openframeworks.cc/download) on the main site.
Expand Down
Loading