├── .gitignore ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── cmake ├── EmscriptenScanDepsFix │ ├── emscan-deps │ ├── emscan-deps.bat │ └── emscan-deps.py └── TargetProperties.cmake └── src ├── CMakeLists.txt └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16...3.29 FATAL_ERROR) 2 | project( 3 | my_project 4 | VERSION 1.0.0 5 | LANGUAGES CXX C 6 | ) 7 | 8 | ####################################### 9 | # Utils 10 | 11 | include(cmake/TargetProperties.cmake) 12 | 13 | ####################################### 14 | # Target definitions 15 | 16 | add_subdirectory(src) 17 | 18 | # Set 'my_project' as the default target in the generated Visual Studio solution 19 | set_property( 20 | DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 21 | PROPERTY VS_STARTUP_PROJECT my_project 22 | ) 23 | 24 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 6, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 28, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "native", 11 | "displayName": "Native", 12 | "description": "Default options for native build", 13 | "binaryDir": "${sourceDir}/build-native" 14 | }, 15 | { 16 | "name": "web", 17 | "displayName": "Web", 18 | "description": "Default options for WebAssembly build", 19 | "binaryDir": "${sourceDir}/build-web", 20 | "cacheVariables": { 21 | "CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS": { 22 | "type": "FILEPATH", 23 | "value": "${sourceDir}/cmake/EmscriptenScanDepsFix/emscan-deps" 24 | } 25 | } 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Elie Michel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | C++20 CMake-Emscripten Template 2 | =============================== 3 | 4 | *Setup for **Native** and **Web** build of **C++20** source code.* 5 | 6 | 🤔 Why this repository? 7 | ----------------------- 8 | 9 | **Problem:** There is currently an issue when using C++20 with Emscripten's `emcmake` ([emscripten#22305](https://github.com/emscripten-core/emscripten/issues/22305)). There is a fix proposed in [PR#21987](https://github.com/emscripten-core/emscripten/pull/21987), but it has not been merged yet. 10 | 11 | **Solution:** This repository provides a minimal setup that **imports the fix** proposed by [PR#21987](https://github.com/emscripten-core/emscripten/pull/21987) **without the need to modify emscripten** itself. 12 | 13 | 🥸 Using as a template 14 | --------------------- 15 | 16 | You may use this repository as a template, then replace the following strings in the code base: 17 | 18 | - `my_project` is the name of the CMake project (and IDE solution). 19 | - `my_target` is the name of the CMake target, i.e., the name of the generated executable or HTML file. 20 | 21 | 🏗️ Building 22 | ----------- 23 | 24 | This is a regular CMake project, that builds like a CMake project. The **only exception** is the extra option needed for Web build (see below). 25 | 26 | These instructions show how to manually call CMake, but a `CMakePresets.json` file is also provided as an alternative. 27 | 28 | ### Native 29 | 30 | ```bash 31 | # Configure 32 | cmake -B build-native 33 | # or 'cmake --preset native' 34 | 35 | # Build 36 | cmake --build build-native 37 | 38 | # Run (Windows & MSVC) 39 | build/src/Debug/my_target.exe 40 | 41 | # Run (other) 42 | build/src/my_target 43 | ``` 44 | 45 | ### WebAssembly 46 | 47 | **NB** *The workaround for issue [emscripten#22305](https://github.com/emscripten-core/emscripten/issues/22305) consists in pointing `CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS` to the local fix that we have in `cmake/EmscriptenScanDepsFix`.* 48 | 49 | ```bash 50 | # Activate emscripten env (Windows) 51 | C:/path/to/emsdk/emsdk_env.bat 52 | 53 | # Activate emscripten env (other) 54 | . /path/to/emsdk/emsdk_env.sh 55 | 56 | # Configure 57 | emcmake cmake -B build -DCMAKE_CXX_COMPILER_CLANG_SCAN_DEPS=cmake/EmscriptenScanDepsFix/emscan-deps 58 | # or 'emcmake cmake --preset web' 59 | 60 | # Build 61 | cmake --build build 62 | 63 | # Host 64 | python -m http.server 8000 65 | # The browse to http://localhost:8000/build-web/src/my_target.html 66 | ``` 67 | -------------------------------------------------------------------------------- /cmake/EmscriptenScanDepsFix/emscan-deps: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2020 The Emscripten Authors. All rights reserved. 3 | # Emscripten is available under two separate licenses, the MIT license and the 4 | # University of Illinois/NCSA Open Source License. Both these licenses can be 5 | # found in the LICENSE file. 6 | # 7 | # Entry point for running python scripts on UNIX systems. 8 | # 9 | # Automatically generated by `create_entry_points.py`; DO NOT EDIT. 10 | # 11 | # To make modifications to this file, edit `tools/run_python.sh` and then run 12 | # `tools/maint/create_entry_points.py` 13 | 14 | # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal 15 | # of cpython used in cross compilation via setup.py. 16 | unset _PYTHON_SYSCONFIGDATA_NAME 17 | 18 | if [ -z "$PYTHON" ]; then 19 | PYTHON=$EMSDK_PYTHON 20 | fi 21 | 22 | if [ -z "$PYTHON" ]; then 23 | PYTHON=$(command -v python3 2> /dev/null) 24 | fi 25 | 26 | if [ -z "$PYTHON" ]; then 27 | PYTHON=$(command -v python 2> /dev/null) 28 | fi 29 | 30 | if [ -z "$PYTHON" ]; then 31 | echo 'unable to find python in $PATH' 32 | exit 1 33 | fi 34 | 35 | exec "$PYTHON" -E "$0.py" "$@" 36 | -------------------------------------------------------------------------------- /cmake/EmscriptenScanDepsFix/emscan-deps.bat: -------------------------------------------------------------------------------- 1 | :: Entry point for running python scripts on windows systems. 2 | :: 3 | :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. 4 | :: 5 | :: To make modifications to this file, edit `tools/run_python.bat` and then run 6 | :: `tools/maint/create_entry_points.py` 7 | 8 | :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, 9 | :: or there will be a parsing error. 10 | 11 | :: All env. vars specified in this file are to be local only to this script. 12 | @setlocal 13 | :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal 14 | :: of cpython used in cross compilation via setup.py. 15 | @set _PYTHON_SYSCONFIGDATA_NAME= 16 | @set EM_PY=%EMSDK_PYTHON% 17 | @if "%EM_PY%"=="" ( 18 | set EM_PY=python 19 | ) 20 | 21 | :: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this 22 | :: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and 23 | :: %~dp0 expansions will not work. 24 | :: So first try if %~dp0 might work, and if not, manually look up this script from PATH. 25 | @if exist "%~f0" ( 26 | set MYDIR=%~dp0 27 | goto FOUND_MYDIR 28 | ) 29 | @for %%I in (%~n0.bat) do ( 30 | @if exist %%~$PATH:I ( 31 | set MYDIR=%%~dp$PATH:I 32 | ) else ( 33 | echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. 34 | echo To help this issue, try removing unnecessary quotes in the invocation of emcc, 35 | echo or add Emscripten directory to PATH. 36 | echo See github.com/microsoft/terminal/issues/15212 and 37 | echo github.com/emscripten-core/emscripten/issues/19207 for more details. 38 | ) 39 | ) 40 | :FOUND_MYDIR 41 | 42 | :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a 43 | :: shared stdin handle from the parent process, and that parent process stdin handle is in 44 | :: a certain state, running python.exe might hang here. To work around this, if 45 | :: EM_WORKAROUND_PYTHON_BUG_34780 is defined, invoke python with '< NUL' stdin to avoid 46 | :: sharing the parent's stdin handle to it, avoiding the hang. 47 | 48 | :: On Windows 7, the compiler batch scripts are observed to exit with a non-zero errorlevel, 49 | :: even when the python executable above did succeed and quit with errorlevel 0 above. 50 | :: On Windows 8 and newer, this issue has not been observed. It is possible that this 51 | :: issue is related to the above python bug, but this has not been conclusively confirmed, 52 | :: so using a separate env. var EM_WORKAROUND_WIN7_BAD_ERRORLEVEL_BUG to enable the known 53 | :: workaround this issue, which is to explicitly quit the calling process with the previous 54 | :: errorlevel from the above command. 55 | 56 | :: Also must use goto to jump to the command dispatch, since we cannot invoke emcc from 57 | :: inside a if() block, because if a cmdline param would contain a char '(' or ')', that 58 | :: would throw off the parsing of the cmdline arg. 59 | @if "%EM_WORKAROUND_PYTHON_BUG_34780%"=="" ( 60 | @if "%EM_WORKAROUND_WIN7_BAD_ERRORLEVEL_BUG%"=="" ( 61 | goto NORMAL 62 | ) else ( 63 | goto NORMAL_EXIT 64 | ) 65 | ) else ( 66 | @if "%EM_WORKAROUND_WIN7_BAD_ERRORLEVEL_BUG%"=="" ( 67 | goto MUTE_STDIN 68 | ) else ( 69 | goto MUTE_STDIN_EXIT 70 | ) 71 | ) 72 | 73 | :NORMAL_EXIT 74 | @"%EM_PY%" -E "%MYDIR%%~n0.py" %* 75 | @exit %ERRORLEVEL% 76 | 77 | :MUTE_STDIN 78 | @"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL 79 | @exit /b %ERRORLEVEL% 80 | 81 | :MUTE_STDIN_EXIT 82 | @"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL 83 | @exit %ERRORLEVEL% 84 | 85 | :NORMAL 86 | @"%EM_PY%" -E "%MYDIR%%~n0.py" %* 87 | -------------------------------------------------------------------------------- /cmake/EmscriptenScanDepsFix/emscan-deps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2024 The Emscripten Authors. All rights reserved. 3 | # Emscripten is available under two separate licenses, the MIT license and the 4 | # University of Illinois/NCSA Open Source License. Both these licenses can be 5 | # found in the LICENSE file. 6 | 7 | """emscan-deps - clang-scan-deps helper script 8 | 9 | This script acts as a frontend replacement for clang-scan-deps. 10 | """ 11 | import sys 12 | import os 13 | from os.path import join 14 | sys.path.insert(0, join(os.environ["EMSDK"], "upstream", "emscripten")) 15 | from tools import shared, cache 16 | 17 | CLANG_SCAN_DEPS = shared.build_llvm_tool_path(shared.exe_suffix('clang-scan-deps')) 18 | 19 | args = sys.argv[1:] 20 | args.append('--sysroot=' + cache.get_sysroot(absolute=True)) 21 | shared.exec_process([CLANG_SCAN_DEPS] + args) 22 | -------------------------------------------------------------------------------- /cmake/TargetProperties.cmake: -------------------------------------------------------------------------------- 1 | # Set the target properties that all targets from this project are using. 2 | function(target_set_common_properties Target) 3 | 4 | set_target_properties(${Target} 5 | PROPERTIES 6 | # C++ 20 is required for co-routines 7 | CXX_STANDARD 20 8 | CXX_STANDARD_REQUIRED ON 9 | CXX_EXTENSIONS OFF 10 | 11 | # Always treat warnings as errors 12 | COMPILE_WARNING_AS_ERROR ON 13 | ) 14 | 15 | # Enable more warnings 16 | if (MSVC) 17 | target_compile_options(${Target} PRIVATE /W4) 18 | else() 19 | target_compile_options(${Target} PRIVATE -Wall -Wextra) 20 | # You may want to selectively remove some warnings here 21 | endif() 22 | 23 | # Place the target in the "co-realm" directory in the IDEs project structure 24 | set_target_properties(${Target} PROPERTIES FOLDER "my_project") 25 | 26 | endfunction(target_set_common_properties) 27 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_executable(my_target) 3 | 4 | target_set_common_properties(my_target) 5 | 6 | target_sources(my_target 7 | PRIVATE 8 | main.cpp 9 | ) 10 | 11 | if (EMSCRIPTEN) 12 | 13 | set_target_properties(my_target PROPERTIES SUFFIX ".html") 14 | 15 | endif (EMSCRIPTEN) 16 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // This is C++20 only 4 | #include 5 | 6 | int main(int, char**) { 7 | std::cout << "Hello, C++ 20!" << std::endl; 8 | 9 | std::cout << "Testing span: (expects 2,3,4,5)" << std::endl; 10 | constexpr int buffer[]{ 0, 1, 2, 3, 4, 5, 6, 7, 8 }; 11 | std::span slice = { buffer + 2, 4 }; 12 | for (int value : slice) { 13 | std::cout << " - " << value << std::endl; 14 | } 15 | 16 | return 0; 17 | } 18 | --------------------------------------------------------------------------------