Skip to content

cmake: make DaemonPlatform, Architecture, Compiler, etc. autonomous and reusable as Yokai framework#1641

Open
illwieckz wants to merge 27 commits into
masterfrom
illwieckz/cmake-platform
Open

cmake: make DaemonPlatform, Architecture, Compiler, etc. autonomous and reusable as Yokai framework#1641
illwieckz wants to merge 27 commits into
masterfrom
illwieckz/cmake-platform

Conversation

@illwieckz

@illwieckz illwieckz commented Apr 7, 2025

Copy link
Copy Markdown
Member

Some revamp of the DaemonPlatform/DaemonArchitecture/DaemonCompiler/DaemonBuildInfo helper code for CMake.

I want this framework to be reusable for other projects, the first user outside of the engine may be the NaCl loader itself, and I may use it for NetRadiant as well at some point. So I made the code fully autonomous and contained in a single folder (so it can be copied and kept it sync easily).

It happens that the endian stuff we did in the DaemonCompiler code using Endian.h was useless (it was not doing better than what the qprocessordetection.h code does anyway), so I removed it.

I also renamed GAME_PIE to NACL_PIE because it's an NaCl option, it was named GAME_PIE because we only build games as NaCl, but for a self-contained framework we better name the NaCl option NACL. For now this code sets GAME_PIE to the NACL_PIE value but once the game is modified to use NACL_PIE the code setting the GAME_PIE alias will be deleted.


Edit: That framework now has its own name: Yokai.

Yokai is the name of that reusable generic CMake framework. CMake variables are prefixed with YOKAI_, C variables and definitions are prefixed with YOKAI_ as well, and the folder for generated files is prefixed with Yokai.

The name is inspired from that third race mod that was named Unvanquished, from which we already inherited the Dæmon name (Dæmon was the third team name along Humans and Aliens, the Yokai model was one of those Dæmons).

@slipher

slipher commented Apr 8, 2025

Copy link
Copy Markdown
Member

Why would we need a variable called NACL_PIE? There is no PIE for NaCl and never will be.

@slipher

slipher commented Oct 9, 2025

Copy link
Copy Markdown
Member

I want this framework to be reusable for other projects

Note that some of the facilities here duplicate CMake built-in functionality, or have more fully developed alternatives available from other projects. Effort is likely to be wasted in such cases:

  • For daemon_write_generated(file.cpp ${contents}), CMake's file(GENERATED OUTPUT file.cpp CONTENTS ${contents}) is a drop-in replacement, modulo daemon_write_generated adding stuff to the path name. See the slipher/cmake-filegenerated branch.
  • The build info stuff largely duplicates the functionality of CMake's configure_file.
  • For a platform-independent resource compiler implemented as CMake script / embedding files (though that's not actually part of this PR currently), there is https://github.com/vector-of-bool/cmrc

DaemonArchitecture looks most likely to be useful. I think I saw a similar thing with SDL, but Daemon's looked more complete.

@slipher

slipher commented Oct 12, 2025

Copy link
Copy Markdown
Member

Why would we need a variable called NACL_PIE? There is no PIE for NaCl and never will be.

Well maybe I'm wrong about that: the native_client scons build has a nacl_pic option. It has an effect only for PNaCl toolchains, not Saigo.

@slipher

slipher commented Oct 12, 2025

Copy link
Copy Markdown
Member

Then again, there is a comment explaining that it is not useful:

# Since PNaCl has no reason to generate PIC at all until there is some
# form of ELF shared object support (if that ever happens at all),
# perhaps we'll never really need to test this.

Also there is another comment confirming that Saigo does not have PIC.

@illwieckz illwieckz force-pushed the illwieckz/cmake-platform branch 2 times, most recently from 745bede to d2b73ca Compare December 9, 2025 06:37
@illwieckz

Copy link
Copy Markdown
Member Author

I removed the unused NaCl PIE thing.

@illwieckz illwieckz changed the title cmake: make DaemonPlatform/Architecture/Compiler/BuildInfo autonomous and reusable cmake: make DaemonPlatform, Architecture, Compiler, etc. autonomous and reusable Dec 9, 2025
@illwieckz illwieckz force-pushed the illwieckz/cmake-platform branch 3 times, most recently from f01bf1f to 10ae04b Compare December 9, 2025 10:06
Comment thread cmake/Yokai/All.cmake
# Collection of reusable CMake helpers written for the Dæmon engine and related
# projects.
################################################################################

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do we need this file? Are some of the files dependent on each other and so have to be included in a specific order?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We need to include them in specific order, and the Compiler stuff (and maybe other things) are writing constants (like compiler name and version) that is generated as source with SourceGenerator to be embedded in the binary.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Also Architecture requires System to be included first so it can select amd64 as NACL_ARCH on arm64 macOS, and things like that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we use this instead? https://cmake.org/cmake/help/v3.17/command/include_guard.html
Then each file can include its own dependencies and the user does not need to take care to call them in a special order.

@illwieckz illwieckz Dec 16, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

You'll end up loading them anyway.

The only thing that seems to be interesting to do is to provide an option to not generate the source files with the various discovered things, for projects not caring about reporting the build environment to the user. For example we don't need such reporting in NaCl.

@illwieckz illwieckz Dec 16, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

With the latest version, if you only include Detection.cmake without having included SourceGenerator.cmake first (or the Platform.cmake entry point which is meant to include everything supported), then no source is generated when detecting the build environment.

@illwieckz illwieckz force-pushed the illwieckz/cmake-platform branch 2 times, most recently from 5d31fb8 to a9191be Compare December 16, 2025 08:54
@illwieckz illwieckz force-pushed the illwieckz/cmake-platform branch from a9191be to cd64470 Compare December 16, 2025 11:19
@illwieckz

Copy link
Copy Markdown
Member Author

I landed my rewrite of System.cmake that does like Compiler.cmake to detect the target system.

This defines variables like DAEMON_HOST_SYSTEM and DAEMON_TARGET_SYSTEM.

A good example of usage of them is to avoid the ambiguity of WIN32.

Instead of WIN32 to detect the target we can use DAEMON_TARGET_SYSTEM_Windows and instead of MSVC and NOT MSVC AND WIN32 to detect the compiler we can use DAEMON_CXX_COMPILER_MSVC and DAEMON_CXX_COMPILER_MinGW.

It may also help to do things differently with MinGW on Linux and MinGW on Windows, when needed.

It may also help in the future as cross-compiler evolves, for example the day Zig becomes suitable for us to cross-compile for macOS on Linux, and things like that.

I also renamed ARCH and NACL_ARCH as DAEMON_ARCH and DAEMON_NACL_ARCH, as I prefer those global variable to be prefixed with DAEMON, especially since I write that DamonPlatform things to be reusable outside of the engine, and short names like ARCH are likely to collide.

@illwieckz illwieckz force-pushed the illwieckz/cmake-platform branch 5 times, most recently from 3227432 to 5712ef4 Compare December 16, 2025 16:21
Comment thread cmake/Yokai/System.cmake Outdated
Comment thread cmake/DaemonFlags.cmake
Comment thread srclibs.cmake Outdated
)
elseif (LINUX)
# We don't know if this works outside of Linux,
# so we don't use YOKAI_TARGET_SYSTEM_LINUX_COMPATIBILITY.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Comment removed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In fact it was indeed meant to be LINUX_COMPATIBILITY, so it can be used on Android even if not a Linux Desktop.

It's just that I defined twice LINUX_COMPATIBILITY, and the second one with another meaning:

Now I use XDG_COMPATIBILITY when the desktop is linux-like, while LINUX_COMPATIBILITY means the Linux API is actually there.

And for completeness, LINUX means Linux desktop, not Android (that one of the ambiguity I also wanted to remove).

Comment thread CMakeLists.txt
@slipher

slipher commented Jun 8, 2026

Copy link
Copy Markdown
Member

I should mention that besides the Clang that pretends to be MSVC, there is also Clang that pretends to be MinGW. I don't have it installed currently so I can't say how the compiler is detected.

@slipher

slipher commented Jun 8, 2026

Copy link
Copy Markdown
Member

I still don't understand the claimed problems with making each cmake file self-contained (by including dependencies using the include_guard thing), or doing NaCl stuff outside of Yokai. daemon_generate_buildinfo is called in Daemon's CMakeLists.txt, and it's still that way after the refactoring. That's a good thing: clients can decide whether they want a build info to be generated, and add their own definitions to it. So making the buildinfo cmake file a dependency of any other file is no problem because it doesn't contribute anything to the build unless generate_buildinfo is called. And Daemon can add its own build infos respecting NaCl after including the Yokai scripts.

(Also I think it's bad how build info is done with gamelogic currently, though that can go in another PR. DaemonGame.cmake currently generates the build info when it's included and then it's hackily included from q_shared.h with ifdefs. Instead of that, the gamelogic should call daemon_generate_buildinfo itself (if it even wants to) and include it from its own files: that way it would have the chance to add its own definitions.)

@illwieckz illwieckz force-pushed the illwieckz/cmake-platform branch 6 times, most recently from 6bfb4db to 95c6284 Compare June 9, 2026 02:33
@illwieckz

Copy link
Copy Markdown
Member Author

The NaCl architecture stuff is now removed from Yokai and stored in cmake/DaemonNaclHost.cmake, it is only called by the engine CMake code. Note that I will probably deeply rewrite this code later, but that's outside of the scope if this PR.

@illwieckz

Copy link
Copy Markdown
Member Author

(Also I think it's bad how build info is done with gamelogic currently, though that can go in another PR. DaemonGame.cmake currently generates the build info when it's included and then it's hackily included from q_shared.h with ifdefs. Instead of that, the gamelogic should call daemon_generate_buildinfo itself (if it even wants to) and include it from its own files: that way it would have the chance to add its own definitions.)

Right now Dæmon's CMakeLists.txt does:

yokai_write_buildinfo("DaemonEngine")

And game's DaemonGame.cmake does:

yokai_write_buildinfo("DaemonGame")

The buildinfo is never mixed between engine and game.

@illwieckz

illwieckz commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

The buildinfo is never mixed between engine and game.

Also the list of things in engine and game buildinfo aren't the same anymore, for example the game buildinfo doesn't have the DAEMON_NACL_ARCH_STRING constant that is engine-only.

Also it's not possible for the game to use engine's buildinfo because the nexe build is done in a subfolder.

The name passed to yokai_write_buildinfo is the name of the subfoler the buildinfo data is written to, to make sure the game doesn't reuse engine buildinfo by mistake when built as dll/exe (and sharing the build folder with the engine).

@slipher

slipher commented Jun 9, 2026

Copy link
Copy Markdown
Member

(Also I think it's bad how build info is done with gamelogic currently, though that can go in another PR. DaemonGame.cmake currently generates the build info when it's included and then it's hackily included from q_shared.h with ifdefs. Instead of that, the gamelogic should call daemon_generate_buildinfo itself (if it even wants to) and include it from its own files: that way it would have the chance to add its own definitions.)

Right now Dæmon's CMakeLists.txt does:

yokai_write_buildinfo("DaemonEngine")

And game's DaemonGame.cmake does:

yokai_write_buildinfo("DaemonGame")

The buildinfo is never mixed between engine and game.

I'm saying the write_buildinfo should be in Unvanquished CMakeLists.txt, not in DaemonGame.cmake. I'm hoping this could fix #1599.

#endif

#if defined(__unix__) || defined(__unix) || defined(unix)
#pragma message(REPORT_COMPATIBILITY("Unix"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I suggest removing this as it has unexpected semantics: Mac OS is a Unix, but does not define these. Anyhow the good old idiom for Unix-like is NOT WIN32 :)

Comment thread cmake/Yokai/System.cmake Outdated
# implementing standards like FHS, XDG, GLVND…
# Makes possible to do that in CMake code:
# > if (YOKAI_HOST_SYSTEM_XDG_COMPATIBILITY)
# > if (YOKAI_SYSTEM_XDG_COMPATIBILITY)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Instead of XDG_COMPATIBILITY I prefer the GNU_COMPATIBILITY name you used in some other places. This makes sense by reflecting the "GNU/Linux" userland/kernel distinction. So we have Linux compatibility include Android's Linux-based kernel, and GNU compatibility including the FreeBSD using a similar userland to the Linux desktops.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Well it's not that great since GNU compatibility could also be confused for the "GNU compiler id" that CMake identifier for GCC. But at least it relates to the "GNU/Linux" meme. For me XDG doesn't suggest the concept you want to get at at all.

@illwieckz illwieckz Jun 9, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In some iterations I wrote GNU too, then switched to XDG. The thing is that GNU means GNU Hurd in System context.

One may say that GNU Linux is probably similar to GNU Hurd, not less then FreeBSD, but well…

The SYSTEM_GNU_COMPATIBILITY in some other places are leftovers remaining from that first iteration I failed to clean-up properly. I'll fix it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed.

Comment thread cmake/DaemonNaclHost.cmake Outdated

set(box64_usage ppc64el riscv64)
if ("${arch_name}" IN_LIST box64_usage)
option(YOKAI_NACL_BOX64_EMULATION "Use Box64 to emulate x86_64 NaCl loader on unsupported platforms" ON)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can go back to its original name

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Especially since I renamed it in C++ code already. 😆️

Now fixed.

@illwieckz illwieckz force-pushed the illwieckz/cmake-platform branch from 95c6284 to 813b85c Compare June 9, 2026 14:14
@illwieckz

Copy link
Copy Markdown
Member Author

I should mention that besides the Clang that pretends to be MSVC, there is also Clang that pretends to be MinGW. I don't have it installed currently so I can't say how the compiler is detected.

Right now this does:

#elif defined(__MINGW64__) || defined(__MINGW32__)
	#pragma message(REPORT_NAME("MinGW"))
#elif defined(__clang__)
	#pragma message(REPORT_NAME("Clang"))

And this doesn't do any:

#pragma message(REPORT_COMPATIBILITY("MinGW"))

So for now I expect it to just be reported as COMPILER_MINGW with COMPILER_CLANG_COMPATIBILITY.

If needed we can make it be reported as COMPILER_CLANG with COMPILER_MINGW_COMPATIBILITY instead, or something like that.

One can use the Yokai/Detection/detect script for a quick preview of what CMake is expected to provide:

$ ./cmake/Yokai/Detection/detect clang
YOKAI_C_COMPILER_GCC_COMPATIBILITY=ON
YOKAI_C_COMPILER_GCC_VERSION=4.2.1
YOKAI_C_COMPILER_CLANG_COMPATIBILITY=ON
YOKAI_C_COMPILER_CLANG_VERSION=18.1.3
YOKAI_C_COMPILER_CLANG_VERSION_STRING=18.1.3 (1)
YOKAI_C_COMPILER_GENERIC_VERSION_STRING=Ubuntu Clang 18.1.3 (1)
YOKAI_C_COMPILER_NAME=Clang
YOKAI_TARGET_SYSTEM_LINUX_COMPATIBILITY=ON
YOKAI_TARGET_SYSTEM_UNIX_COMPATIBILITY=ON
YOKAI_TARGET_SYSTEM_NAME=Linux
YOKAI_TARGET_ARCH_NAME=amd64

$ ./cmake/Yokai/Detection/detect aarch64-linux-android29-clang
YOKAI_C_COMPILER_GCC_COMPATIBILITY=ON
YOKAI_C_COMPILER_GCC_VERSION=4.2.1
YOKAI_C_COMPILER_CLANG_COMPATIBILITY=ON
YOKAI_C_COMPILER_CLANG_VERSION=9.0.8
YOKAI_C_COMPILER_CLANG_VERSION_STRING=9.0.8 (https://android.googlesource.com/toolchain/llvm-project 207d7abc1a2abf3ef8d4301736d6a7ebc224a290)
YOKAI_C_COMPILER_GENERIC_VERSION_STRING=4.2.1 Compatible Android (5900059 based on r365631c) Clang 9.0.8 (https://android.googlesource.com/toolchain/llvm-project 207d7abc1a2abf3ef8d4301736d6a7ebc224a290)
YOKAI_C_COMPILER_NAME=Clang
YOKAI_TARGET_SYSTEM_LINUX_COMPATIBILITY=ON
YOKAI_TARGET_SYSTEM_UNIX_COMPATIBILITY=ON
YOKAI_TARGET_SYSTEM_NAME=Android
YOKAI_TARGET_ARCH_NAME=arm64

$ ./cmake/Yokai/Detection/detect i686-w64-mingw32-gcc
YOKAI_C_COMPILER_GCC_COMPATIBILITY=ON
YOKAI_C_COMPILER_GCC_VERSION=13.0.0
YOKAI_C_COMPILER_GENERIC_VERSION_STRING=13-posix
YOKAI_C_COMPILER_NAME=MinGW
YOKAI_TARGET_SYSTEM_NAME=Windows
YOKAI_TARGET_ARCH_NAME=i686

@illwieckz illwieckz force-pushed the illwieckz/cmake-platform branch 4 times, most recently from 4ce1846 to 726fb11 Compare June 9, 2026 17:12
@illwieckz illwieckz changed the title cmake: make DaemonPlatform, Architecture, Compiler, etc. autonomous and reusable cmake: make DaemonPlatform, Architecture, Compiler, etc. autonomous and reusable as Yokai framework Jun 9, 2026

# Make sure to always call this macro from within a function, not in the global scope.
# As a macro it produces a lot of variables in the parent scope but it is meant to
# only be called by functions so they should never pollute the globale scope.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

"globale"

PARENT_SCOPE)
endforeach()
endif()
yokai_run_detection("${lang}" "COMPILER" "Compiler${${lang}_EXT}" "GCC;Clang;generic")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

"generic" string seems to be unused

Comment thread cmake/DaemonFlags.cmake
endif()

if (NACL AND USE_NACL_SAIGO AND SAIGO_ARCH STREQUAL "arm")
if (YOKAI_TARGET_SYSTEM_NACL AND USE_NACL_SAIGO AND YOKAI_NACL_ARCH_armhf)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

missed capitalization spot?

Comment thread cmake/DaemonFlags.cmake
if (YOKAI_CXX_COMPILER_ICC)
set(GCC_GENERIC_ARCH "pentium4")
elseif (DAEMON_CXX_COMPILER_Zig)
elseif (YOKAI_CXX_COMPILER_Zig)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

missed capitalization spot?

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.

2 participants