Skip to content

CMake build system for the core and apps (macOS, iOS, tvOS, Emscripten, Linux, Windows) - #8586

Open
danoli3 wants to merge 15 commits into
openframeworks:masterfrom
danoli3:cmake-build-system
Open

danoli3 wants to merge 15 commits into
openframeworks:masterfrom
danoli3:cmake-build-system

Conversation

@danoli3

@danoli3 danoli3 commented Oct 13, 2026

Copy link
Copy Markdown
Member

A CMake build for the openFrameworks core and apps on every desktop, web and Apple platform, built the same way as Android's: a core project, and an app template that links it. Next, the Project Generator can write CMakeLists.txt projects.

Draft: Windows (Visual Studio, MSYS2) is written but not yet built; a Windows test run is next.

Usage

Copy scripts/templates/cmake/CMakeLists.txt into a project:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
  • Sources come from src/, addons from addons.make, or of_add_app(myApp ADDONS ofxGui ofxOsc).
  • The app goes into bin/, named <app> (Release) or <app>_debug (Debug).
  • The core is linked from libs/openFrameworksCompiled/lib/<platform>. If it isn't there for the configuration being built, it's built first and written there for the next app. -DOF_BUILD_CORE=ON always rebuilds it.

Per-platform commands, options and the PG integration are in libs/openFrameworksCompiled/project/CMake/README.md.

What it mirrors

platform/<family>.cmake holds each platform's settings, taken from its makefile config or IDE project:

  • core exclusions, defines and flags
  • frameworks, system and pkg-config libraries
  • third-party libraries from libs/*/lib/<platform>
  • the app output
Platform Output Core (same file as the existing builds)
macOS bin/<app>.app: Info.plist from the project or template, icon lib/macos/openFrameworks.a (Xcode's)
iOS / tvOS bin/<app>.app: xcframeworks, bin/data and mediaAssets in the bundle lib/ios/<sdk>/openFrameworksiOS.a, lib/tvos/<sdk>/openFrameworkstvOS.a
Emscripten bin/em/<app>/index.html with bin/data preloaded, plus app.js and style.css lib/emscripten/libopenFrameworks.a
Linux bin/<app> lib/<platform>/libopenFrameworks.a (make's)
Visual Studio bin/<app>.exe lib/vs/<arch>/openframeworksLib.lib (the VS project's)
MSYS2 bin/<app>.exe lib/msys2/libopenFrameworks.a (make's)

Addons are read the same way as the makefiles:

  • sources, include paths and libraries from the addon's folders
  • addon_config.mk sections, = / +=, % wildcards, ADDON_DEPENDENCIES and ADDON_*_EXCLUDE

of_target_addon_files() takes explicit lists instead, so the Project Generator can write out the addons it has already resolved.

Tested

Platform Core Apps built and run
macOS 26, AppleClang 21: Ninja and Xcode, Release and Debug ✅ emptyExample, graphicsExample, guiExample (ofxGui)
Emscripten 6.0.11, headless Chrome ✅ graphicsExample, guiExample, 0 errors
Linux aarch64, Ubuntu 24.04, GCC 13 (Docker, Xvfb) ✅ emptyExample, graphicsExample, guiExample
iOS 26 simulator, Xcode generator ✅ graphicsExample
tvOS 26 simulator, Xcode generator ✅ emptyExample, ofBoxExample
Visual Studio, MSYS2 not yet test run pending

Known: opencvExample on macOS fails to link, with undefined kleidicv:: symbols. The make build fails identically: apothecary's macOS OpenCV xcframework is missing KleidiCV.

Differences from the makefiles

  • Third-party include paths: only libs/*/include roots are added, as in the Xcode and VS projects. The makefiles also add every subfolder, and on iOS that lets glm/include/glm/simd shadow the SDK's <simd/…> headers. Addons keep the makefiles' recursive includes.
  • Opt-in renderers: Dawn and MetalANGLE are left out unless OF_USE_DAWN / OF_USE_ANGLE are set.
  • Core file: the macOS core is Xcode's lib/macos/openFrameworks.a rather than make's lib/osx/libopenFrameworks.a.

Android keeps its own CMake; moving it onto this system is a follow-up.

libs/openFrameworksCompiled/project/CMake builds the openFrameworks core
and apps on macOS, iOS, tvOS, Emscripten, Linux (linux64, linuxaarch64,
linuxarmv7l, linuxarmv6l), Visual Studio and MSYS2, mirroring the
makefiles and IDE projects: the same sources, defines, flags and
third-party libraries per platform, apps built into bin/, and the core in
libs/openFrameworksCompiled/lib/<platform> with the names the existing
builds use. Android keeps its own CMake for now.

- openFrameworks.cmake: entry point for apps and the core project
- CMakeLists.txt: the core library project
- OFCore.cmake: core sources, third-party libs, the openFrameworks and
  openFrameworks::deps targets; apps link the prebuilt core, or build it
  first if it isn't there (OF_BUILD_CORE=ON forces that)
- OFAddons.cmake: addons from their folders and addon_config.mk like the
  makefiles, or from explicit lists (of_target_addon_files, for the
  Project Generator)
- OFApp.cmake: of_add_app()
- platform/*.cmake: per platform excludes, defines, flags, libraries and
  app output (.app bundles with Info.plist and icon, bin/em/<app> for
  Emscripten, xcframeworks and bin/data in the bundle on iOS / tvOS)

scripts/templates/cmake/CMakeLists.txt is the app template; generated
CMakeLists.txt in examples are ignored like the Makefiles.
PROJECT_EMSCRIPTEN_WASM (32 / 64), PROJECT_EMSCRIPTEN_TOTAL_MEMORY,
PROJECT_EMSCRIPTEN_EMBIND_AOT and PROJECT_EMSCRIPTEN_TEMPLATE, as in a
project's config.make, so the Project Generator writes the same setting
for both. wasm64 builds the core into lib/emscripten/WASM64 like the
makefiles; EMSCRIPTEN_MEMORY64 still selects 64.
Same names as the makefiles' config.make (openframeworks#8592): APP_VERSION sets
CFBundleShortVersionString (default: project(... VERSION), else 1.0) and
APP_BUILD sets CFBundleVersion (default 1), also as Xcode's
MARKETING_VERSION / CURRENT_PROJECT_VERSION.

Based on openframeworks#3394.

Co-authored-by: Vincent Donnefort <vdonnefort@gmail.com>
@danoli3

danoli3 commented Oct 16, 2026

Copy link
Copy Markdown
Member Author

Added APP_VERSION / APP_BUILD for the macOS / iOS / tvOS Info.plist. These are the same names as the makefiles' config.make option in #8592, which brings back #3394.

  • Setting them: set(APP_VERSION 2.3.4) / set(APP_BUILD 42) before of_add_app(), or -DAPP_VERSION=… -DAPP_BUILD=….
  • Defaults: the version falls back to project(… VERSION x.y), then 1.0; the build defaults to 1.
  • Tested on macOS with emptyExample: defaults gave 1.0 / 1, -D gave 2.3.4 / 42, and project(VERSION 5.6.7) gave 5.6.7. plutil -lint passes.

@danoli3
danoli3 marked this pull request as ready for review October 18, 2026 04:20
scripts/ci/cmake/build.sh builds the core (Release and Debug) with the CMake
project, then emptyExample (Release and Debug), graphicsExample, guiExample
and allAddonsExample. Each example's CMakeLists.txt comes from
projectGenerator -t cmake when --pg is given (linux64 and VS use the nightly
PG), otherwise from scripts/templates/cmake/CMakeLists.txt. A failed step
fails the job with an ::error annotation, and each app must end up in bin/.
Link the core archive with --whole-archive. Keep wasm32 and wasm64 libraries in separate folders, default embind AOT off, and drop MAIN_MODULE so audio worklets link.
The vcxproj sets CharacterSet to Unicode. Without UNICODE and _UNICODE, Win32 calls stay on the ANSI entry points and the wide paths in ofFileUtils and ofSystemUtils do not compile.
icon.rc names icon.ico / icon_debug.ico, which live in project/vs; the VS
template adds that folder to the resource compiler's include path, so do the
same for the CMake app target.
Release and Debug libs are generator expressions ending in .lib>. The addon filter only kept paths ending in .lib, so ofxAssimpModelLoader and ofxOpenCv linked with no libraries.
Keep platform-generated library expressions intact during addon path expansion and filtering. Verify split Debug/Release directories, flat paired libraries and shared libraries in the CMake CI entry point.
@danoli3

danoli3 commented Oct 19, 2026

Copy link
Copy Markdown
Member Author

Fixed opencv issues with library changes. I think this is ready for developer tests if wanted

danoli3 and others added 4 commits October 19, 2026 17:23
linuxaarch64 (64-bit Raspberry Pi OS / arm64 Linux) builds natively on
ubuntu-24.04-arm with the aarch64 libs and the nightly arm64
projectGenerator. Emscripten builds in the same emsdk image as
build-emscripten, configured through emcmake, with emptyExample (Release,
Debug), graphicsExample and guiExample.

scripts/ci/cmake/build.sh takes CMAKE_WRAPPER (prefix for the configure
step) and OF_CMAKE_EXAMPLES (replaces the example list), and accepts the
Emscripten output bin/em/<app>/index.html.
LINKER: is only expanded in link options. In target_link_libraries it went
to wasm-ld as -lLINKER:--whole-archive,... and the link failed. Pass it with
target_link_options and add the archive to INTERFACE_LINK_DEPENDS so apps
relink when the core changes.

CI: install libblas-dev / liblapack-dev for build-cmake (linuxaarch64);
ofxOpenCv links -lblas -llapack there, which rpi-build gets from multistrap.
-DOF_BUILD_TESTS=ON on the core build adds every test in tests/ (desktop
platforms) as an app and registers it with add_test, so ctest runs them. Each
test runs from its executable's folder like make RunDebug (bin/, or
Contents/MacOS on macOS, which the fileUtils data path checks expect).

of_add_app takes PROJECT_DIR so projects without a CMakeLists.txt (tests,
examples) can be added; the addon and platform helpers read the project
folder from OF_PROJECT_DIR. OFProjects.cmake walks <root>/<group>/<project>
and skips groups for other platforms.

jsonTest includes <nlohmann/json.hpp> like ofJson.h; "json.hpp" only built
with make, which adds every libs/*/include subfolder.

CI: build-cmake (linux64, macos) builds the tests in Debug and runs ctest.

Based on the CTest setup (define_test) in openframeworks#7524.

Co-authored-by: HerrNamenlos123 <herrnamenlos123@gmail.com>
-DOF_BUILD_EXAMPLES=ON on the core build adds every example for the platform
as an app (EXCLUDE_FROM_ALL, built into its own bin/) and a
build_all_examples target. USE_FOLDERS groups the targets as openFrameworks,
examples/<group> and tests/<group>, so one Visual Studio solution, Xcode
project or CLion project opens them all.

On macOS all 157 examples build (svgParseExample, svgSaveExample and
yunetFaceDetection need the addons.make files they're missing on master).

Based on the examples setup (define_example, build_all_examples, IDE
folders) in openframeworks#7524.

Co-authored-by: HerrNamenlos123 <herrnamenlos123@gmail.com>
-DOF_PRECOMPILED_HEADER=ON precompiles ofMain.h for the app's own src/ C++
files. Addon and library sources skip it (SKIP_PRECOMPILE_HEADERS), so
third-party code compiles as it does in the other build systems. On macOS,
where C++ is compiled as Objective-C++, the header is built as Objective-C++
too, otherwise clang rejects it.

CI: build-cmake (linuxaarch64, vs-x64) builds with the precompiled header,
so GCC and MSVC are covered. build.sh reports the first output it finds.

Based on the precompiled header setup documented in
openframeworks#7524.

Co-authored-by: HerrNamenlos123 <herrnamenlos123@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant