xref: /aosp_15_r20/external/swiftshader/third_party/marl/CMakeLists.txt (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1# Copyright 2019 The Marl Authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15cmake_minimum_required(VERSION 3.0)
16
17include(cmake/parse_version.cmake)
18parse_version("${CMAKE_CURRENT_SOURCE_DIR}/CHANGES.md" MARL)
19
20set(CMAKE_CXX_STANDARD 11)
21
22project(Marl
23    VERSION   "${MARL_VERSION_MAJOR}.${MARL_VERSION_MINOR}.${MARL_VERSION_PATCH}"
24    LANGUAGES C CXX ASM
25)
26
27if (EMSCRIPTEN)
28    add_compile_options(-O3 -pthread)
29endif()
30
31include(CheckCXXSourceCompiles)
32
33# MARL_IS_SUBPROJECT is 1 if added via add_subdirectory() from another project.
34get_directory_property(MARL_IS_SUBPROJECT PARENT_DIRECTORY)
35if(MARL_IS_SUBPROJECT)
36    set(MARL_IS_SUBPROJECT 1)
37endif()
38
39###########################################################
40# Options
41###########################################################
42function(option_if_not_defined name description default)
43    if(NOT DEFINED ${name})
44        option(${name} ${description} ${default})
45    endif()
46endfunction()
47
48option_if_not_defined(MARL_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF)
49option_if_not_defined(MARL_BUILD_EXAMPLES "Build example applications" OFF)
50option_if_not_defined(MARL_BUILD_TESTS "Build tests" OFF)
51option_if_not_defined(MARL_BUILD_BENCHMARKS "Build benchmarks" OFF)
52option_if_not_defined(MARL_BUILD_SHARED "Build marl as a shared / dynamic library (default static)" OFF)
53option_if_not_defined(MARL_USE_PTHREAD_THREAD_LOCAL "Use pthreads for thread local storage" OFF)
54option_if_not_defined(MARL_ASAN "Build marl with address sanitizer" OFF)
55option_if_not_defined(MARL_MSAN "Build marl with memory sanitizer" OFF)
56option_if_not_defined(MARL_TSAN "Build marl with thread sanitizer" OFF)
57option_if_not_defined(MARL_UBSAN "Build marl with undefined-behavior sanitizer" OFF)
58option_if_not_defined(MARL_INSTALL "Create marl install target" OFF)
59option_if_not_defined(MARL_FULL_BENCHMARK "Run benchmarks for [0 .. numLogicalCPUs] with no stepping" OFF)
60option_if_not_defined(MARL_FIBERS_USE_UCONTEXT "Use ucontext instead of assembly for fibers (ignored for platforms that do not support ucontext)" OFF)
61option_if_not_defined(MARL_DEBUG_ENABLED "Enable debug checks even in release builds" OFF)
62
63###########################################################
64# Directories
65###########################################################
66function(set_if_not_defined name value)
67    if(NOT DEFINED ${name})
68        set(${name} ${value} PARENT_SCOPE)
69    endif()
70endfunction()
71
72set(MARL_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
73set(MARL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
74set_if_not_defined(MARL_THIRD_PARTY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party)
75set_if_not_defined(MARL_GOOGLETEST_DIR ${MARL_THIRD_PARTY_DIR}/googletest)
76set_if_not_defined(MARL_BENCHMARK_DIR ${MARL_THIRD_PARTY_DIR}/benchmark)
77
78###########################################################
79# Submodules
80###########################################################
81if(MARL_BUILD_TESTS)
82    if(NOT EXISTS ${MARL_GOOGLETEST_DIR}/.git)
83        message(WARNING "third_party/googletest submodule missing.")
84        message(WARNING "Run: `git submodule update --init` to build tests.")
85        set(MARL_BUILD_TESTS OFF)
86    endif()
87endif(MARL_BUILD_TESTS)
88
89if(MARL_BUILD_BENCHMARKS)
90    if(NOT EXISTS ${MARL_BENCHMARK_DIR}/.git)
91        message(WARNING "third_party/benchmark submodule missing.")
92        message(WARNING "Run: `git submodule update --init` to build benchmarks.")
93        set(MARL_BUILD_BENCHMARKS OFF)
94    endif()
95endif(MARL_BUILD_BENCHMARKS)
96
97if(MARL_BUILD_BENCHMARKS)
98    set(BENCHMARK_ENABLE_TESTING FALSE CACHE BOOL FALSE FORCE)
99    add_subdirectory(${MARL_BENCHMARK_DIR})
100endif(MARL_BUILD_BENCHMARKS)
101
102###########################################################
103# Compiler feature tests
104###########################################################
105# Check that the Clang Thread Safety Analysis' try_acquire_capability behaves
106# correctly. This is broken on some earlier versions of clang.
107# See: https://bugs.llvm.org/show_bug.cgi?id=32954
108set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
109set(CMAKE_REQUIRED_FLAGS "-Wthread-safety -Werror")
110check_cxx_source_compiles(
111    "int main() {
112      struct __attribute__((capability(\"mutex\"))) Mutex {
113        void Unlock() __attribute__((release_capability)) {};
114        bool TryLock() __attribute__((try_acquire_capability(true))) { return true; };
115      };
116      Mutex m;
117      if (m.TryLock()) {
118        m.Unlock();  // Should not warn.
119      }
120      return 0;
121    }"
122    MARL_THREAD_SAFETY_ANALYSIS_SUPPORTED)
123set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS})
124
125# Check whether ucontext is supported.
126set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
127set(CMAKE_REQUIRED_FLAGS "-Werror")
128check_cxx_source_compiles(
129    "#include <ucontext.h>
130    int main() {
131      ucontext_t ctx;
132      getcontext(&ctx);
133      makecontext(&ctx, nullptr, 2, 1, 2);
134      swapcontext(&ctx, &ctx);
135      return 0;
136    }"
137    MARL_UCONTEXT_SUPPORTED)
138set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS})
139if (MARL_FIBERS_USE_UCONTEXT AND NOT MARL_UCONTEXT_SUPPORTED)
140    # Disable MARL_FIBERS_USE_UCONTEXT and warn if MARL_UCONTEXT_SUPPORTED is 0.
141    message(WARNING "MARL_FIBERS_USE_UCONTEXT is enabled, but ucontext is not supported by the target. Disabling")
142    set(MARL_FIBERS_USE_UCONTEXT 0)
143endif()
144
145if(MARL_IS_SUBPROJECT)
146    # Export supported flags as this may be useful to parent projects
147    set(MARL_THREAD_SAFETY_ANALYSIS_SUPPORTED PARENT_SCOPE ${MARL_THREAD_SAFETY_ANALYSIS_SUPPORTED})
148    set(MARL_UCONTEXT_SUPPORTED               PARENT_SCOPE ${MARL_UCONTEXT_SUPPORTED})
149endif()
150
151###########################################################
152# File lists
153###########################################################
154set(MARL_LIST
155    ${MARL_SRC_DIR}/debug.cpp
156    ${MARL_SRC_DIR}/memory.cpp
157    ${MARL_SRC_DIR}/scheduler.cpp
158    ${MARL_SRC_DIR}/thread.cpp
159    ${MARL_SRC_DIR}/trace.cpp
160)
161if(NOT MSVC)
162    list(APPEND MARL_LIST
163        ${MARL_SRC_DIR}/osfiber_aarch64.c
164        ${MARL_SRC_DIR}/osfiber_arm.c
165        ${MARL_SRC_DIR}/osfiber_asm_aarch64.S
166        ${MARL_SRC_DIR}/osfiber_asm_arm.S
167        ${MARL_SRC_DIR}/osfiber_asm_loongarch64.S
168        ${MARL_SRC_DIR}/osfiber_asm_mips64.S
169        ${MARL_SRC_DIR}/osfiber_asm_ppc64.S
170        ${MARL_SRC_DIR}/osfiber_asm_rv64.S
171        ${MARL_SRC_DIR}/osfiber_asm_x64.S
172        ${MARL_SRC_DIR}/osfiber_asm_x86.S
173        ${MARL_SRC_DIR}/osfiber_loongarch64.c
174        ${MARL_SRC_DIR}/osfiber_mips64.c
175        ${MARL_SRC_DIR}/osfiber_ppc64.c
176        ${MARL_SRC_DIR}/osfiber_rv64.c
177        ${MARL_SRC_DIR}/osfiber_x64.c
178        ${MARL_SRC_DIR}/osfiber_x86.c
179        ${MARL_SRC_DIR}/osfiber_emscripten.cpp
180    )
181    # CMAKE_OSX_ARCHITECTURES settings aren't propagated to assembly files when
182    # building for Apple platforms (https://gitlab.kitware.com/cmake/cmake/-/issues/20771),
183    # we treat assembly files as C files to work around this bug.
184    set_source_files_properties(
185        ${MARL_SRC_DIR}/osfiber_asm_aarch64.S
186        ${MARL_SRC_DIR}/osfiber_asm_arm.S
187        ${MARL_SRC_DIR}/osfiber_asm_loongarch64.S
188        ${MARL_SRC_DIR}/osfiber_asm_mips64.S
189        ${MARL_SRC_DIR}/osfiber_asm_ppc64.S
190        ${MARL_SRC_DIR}/osfiber_asm_x64.S
191        ${MARL_SRC_DIR}/osfiber_asm_x86.S
192        PROPERTIES LANGUAGE C
193    )
194endif(NOT MSVC)
195
196###########################################################
197# OS libraries
198###########################################################
199find_package(Threads REQUIRED)
200
201###########################################################
202# Functions
203###########################################################
204function(marl_set_target_options target)
205    if(MARL_THREAD_SAFETY_ANALYSIS_SUPPORTED)
206        target_compile_options(${target} PRIVATE "-Wthread-safety")
207    endif()
208
209    # Enable all warnings
210    if(MSVC)
211        target_compile_options(${target} PRIVATE "-W4")
212    else()
213        target_compile_options(${target} PRIVATE "-Wall")
214    endif()
215
216    # Disable specific, pedantic warnings
217    if(MSVC)
218        target_compile_options(${target} PRIVATE
219            "-D_CRT_SECURE_NO_WARNINGS"
220            "/wd4127" # conditional expression is constant
221            "/wd4324" # structure was padded due to alignment specifier
222        )
223    endif()
224
225    # Treat all warnings as errors
226    if(MARL_WARNINGS_AS_ERRORS)
227        if(MSVC)
228            target_compile_options(${target} PRIVATE "/WX")
229        else()
230            target_compile_options(${target} PRIVATE "-Werror")
231        endif()
232    endif(MARL_WARNINGS_AS_ERRORS)
233
234    if(MARL_USE_PTHREAD_THREAD_LOCAL)
235        target_compile_definitions(${target} PRIVATE "MARL_USE_PTHREAD_THREAD_LOCAL=1")
236        target_link_libraries(${target} PUBLIC pthread)
237    endif()
238
239    if(MARL_ASAN)
240        target_compile_options(${target} PUBLIC "-fsanitize=address")
241        target_link_libraries(${target} PUBLIC "-fsanitize=address")
242    elseif(MARL_MSAN)
243        target_compile_options(${target} PUBLIC "-fsanitize=memory")
244        target_link_libraries(${target} PUBLIC "-fsanitize=memory")
245    elseif(MARL_TSAN)
246        target_compile_options(${target} PUBLIC "-fsanitize=thread")
247        target_link_libraries(${target} PUBLIC "-fsanitize=thread")
248    elseif(MARL_UBSAN)
249        target_compile_options(${target} PUBLIC "-fsanitize=undefined")
250        target_link_libraries(${target} PUBLIC "-fsanitize=undefined")
251    endif()
252
253    if(MARL_FIBERS_USE_UCONTEXT)
254        target_compile_definitions(${target} PRIVATE "MARL_FIBERS_USE_UCONTEXT=1")
255    endif()
256
257    if(MARL_DEBUG_ENABLED)
258        target_compile_definitions(${target} PRIVATE "MARL_DEBUG_ENABLED=1")
259    endif()
260
261    if(CMAKE_SYSTEM_PROCESSOR MATCHES "^rv.*")
262        target_link_libraries(${target} INTERFACE atomic) #explicitly use -latomic for RISC-V linking
263    endif()
264
265    target_include_directories(${target} PUBLIC $<BUILD_INTERFACE:${MARL_INCLUDE_DIR}>)
266endfunction(marl_set_target_options)
267
268###########################################################
269# Targets
270###########################################################
271
272# marl
273if(MARL_BUILD_SHARED OR BUILD_SHARED_LIBS)
274    add_library(marl SHARED ${MARL_LIST})
275    if(MSVC)
276        target_compile_definitions(marl
277            PRIVATE "MARL_BUILDING_DLL=1"
278            PUBLIC  "MARL_DLL=1"
279        )
280    endif()
281else()
282    add_library(marl ${MARL_LIST})
283endif()
284
285if(NOT MSVC)
286    # Public API symbols are made visible with the MARL_EXPORT annotation.
287    target_compile_options(marl PRIVATE "-fvisibility=hidden")
288endif()
289
290set_target_properties(marl PROPERTIES
291    POSITION_INDEPENDENT_CODE 1
292    VERSION ${MARL_VERSION}
293    SOVERSION "${MARL_VERSION_MAJOR}"
294)
295
296marl_set_target_options(marl)
297
298target_link_libraries(marl PUBLIC Threads::Threads)
299
300# install
301if(MARL_INSTALL)
302    include(CMakePackageConfigHelpers)
303    include(GNUInstallDirs)
304
305    configure_package_config_file(
306        ${CMAKE_CURRENT_SOURCE_DIR}/cmake/marl-config.cmake.in
307        ${CMAKE_CURRENT_BINARY_DIR}/marl-config.cmake
308        INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/marl
309    )
310
311    install(DIRECTORY ${MARL_INCLUDE_DIR}/marl
312        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
313        USE_SOURCE_PERMISSIONS
314    )
315
316    install(TARGETS marl
317        EXPORT marl-targets
318        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
319        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
320        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
321        INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
322    )
323
324    install(EXPORT marl-targets
325        FILE marl-targets.cmake
326        NAMESPACE marl::
327        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/marl
328    )
329
330    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/marl-config.cmake
331        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/marl
332    )
333endif(MARL_INSTALL)
334
335# tests
336if(MARL_BUILD_TESTS)
337    set(MARL_TEST_LIST
338        ${MARL_SRC_DIR}/blockingcall_test.cpp
339        ${MARL_SRC_DIR}/conditionvariable_test.cpp
340        ${MARL_SRC_DIR}/containers_test.cpp
341        ${MARL_SRC_DIR}/dag_test.cpp
342        ${MARL_SRC_DIR}/defer_test.cpp
343        ${MARL_SRC_DIR}/event_test.cpp
344        ${MARL_SRC_DIR}/marl_test.cpp
345        ${MARL_SRC_DIR}/marl_test.h
346        ${MARL_SRC_DIR}/memory_test.cpp
347        ${MARL_SRC_DIR}/osfiber_test.cpp
348        ${MARL_SRC_DIR}/parallelize_test.cpp
349        ${MARL_SRC_DIR}/pool_test.cpp
350        ${MARL_SRC_DIR}/scheduler_test.cpp
351        ${MARL_SRC_DIR}/thread_test.cpp
352        ${MARL_SRC_DIR}/ticket_test.cpp
353        ${MARL_SRC_DIR}/waitgroup_test.cpp
354        ${MARL_GOOGLETEST_DIR}/googletest/src/gtest-all.cc
355        ${MARL_GOOGLETEST_DIR}/googlemock/src/gmock-all.cc
356    )
357
358    set(MARL_TEST_INCLUDE_DIR
359        ${MARL_GOOGLETEST_DIR}/googletest/include/
360        ${MARL_GOOGLETEST_DIR}/googlemock/include/
361        ${MARL_GOOGLETEST_DIR}/googletest/
362        ${MARL_GOOGLETEST_DIR}/googlemock/
363    )
364
365    add_executable(marl-unittests ${MARL_TEST_LIST})
366
367    set_target_properties(marl-unittests PROPERTIES
368        INCLUDE_DIRECTORIES "${MARL_TEST_INCLUDE_DIR}"
369        FOLDER "Tests"
370    )
371
372    marl_set_target_options(marl-unittests)
373
374    target_link_libraries(marl-unittests PRIVATE marl)
375endif(MARL_BUILD_TESTS)
376
377# benchmarks
378if(MARL_BUILD_BENCHMARKS)
379    set(MARL_BENCHMARK_LIST
380        ${MARL_SRC_DIR}/blockingcall_bench.cpp
381        ${MARL_SRC_DIR}/defer_bench.cpp
382        ${MARL_SRC_DIR}/event_bench.cpp
383        ${MARL_SRC_DIR}/marl_bench.cpp
384        ${MARL_SRC_DIR}/non_marl_bench.cpp
385        ${MARL_SRC_DIR}/scheduler_bench.cpp
386        ${MARL_SRC_DIR}/ticket_bench.cpp
387        ${MARL_SRC_DIR}/waitgroup_bench.cpp
388    )
389
390    add_executable(marl-benchmarks ${MARL_BENCHMARK_LIST})
391    set_target_properties(${target} PROPERTIES FOLDER "Benchmarks")
392
393    marl_set_target_options(marl-benchmarks)
394
395    target_compile_definitions(marl-benchmarks PRIVATE
396        "MARL_FULL_BENCHMARK=${MARL_FULL_BENCHMARK}"
397    )
398
399    target_link_libraries(marl-benchmarks PRIVATE benchmark::benchmark marl)
400endif(MARL_BUILD_BENCHMARKS)
401
402# examples
403if(MARL_BUILD_EXAMPLES)
404    function(build_example target)
405        add_executable(${target} "${CMAKE_CURRENT_SOURCE_DIR}/examples/${target}.cpp")
406        set_target_properties(${target} PROPERTIES FOLDER "Examples")
407        marl_set_target_options(${target})
408        target_link_libraries(${target} PRIVATE marl)
409        if (EMSCRIPTEN)
410            target_link_options(${target} PRIVATE
411                    -O1
412                    -pthread -sPTHREAD_POOL_SIZE=2 -sPROXY_TO_PTHREAD
413                    -sASYNCIFY # -sASYNCIFY_STACK_SIZE=1000000
414                    -sALLOW_MEMORY_GROWTH=1 -sASSERTIONS
415                    -sENVIRONMENT=web,worker
416                    "SHELL:--shell-file ${CMAKE_CURRENT_SOURCE_DIR}/examples/shell.emscripten.html")
417            set_target_properties(${target} PROPERTIES SUFFIX .html)
418        endif()
419    endfunction(build_example)
420
421    build_example(fractal)
422    build_example(hello_task)
423    build_example(primes)
424    build_example(tasks_in_tasks)
425endif(MARL_BUILD_EXAMPLES)
426