Merge branch 'main' of https://libneat.hopto.org/git/kevin/rtengine
Some checks failed
Ubuntu Cross to Win64 / Cross Compile with ming64 (1.4.0, ubuntu-latest) (push) Failing after 1m18s

This commit is contained in:
Kevin Trogant 2024-07-19 10:31:30 +02:00
commit 14138b4933
25 changed files with 149 additions and 62 deletions

View File

@ -26,21 +26,17 @@ jobs:
steps: steps:
- name: Checkout Code - name: Checkout Code
uses: https://gitea.com/ScMi1/checkout@v1 uses: https://gitea.com/ScMi1/checkout@v1
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install PIP Dependencies
run: python -m pip install meson==${{ matrix.meson_version }} ninja
- name: Install APT Dependencies - name: Install APT Dependencies
run: | run: |
apt update -y apt update -y
apt install -y cmake clang build-essential libwayland-dev libxkbcommon-dev xorg-dev mingw-w64 wine-stable apt install -y python3-pip cmake clang build-essential libwayland-dev libxkbcommon-dev xorg-dev mingw-w64 mingw-w64-common wine-stable
- name: Install PIP Dependencies
run: python -m pip install meson==${{ matrix.meson_version }} ninja
- name: Configure Project - name: Configure Project
run: | run: |
chmod +x ./scripts/download_dxc_cross.sh chmod +x ./scripts/download_dxc_cross.sh
./scripts/download_dxc_cross.sh ./scripts/download_dxc_cross.sh
meson setup --cross-file scripts/x86_64-w64-mingw32.txt build meson setup --cross-file scripts/x86_64-w64-mingw32.txt -Db_sanitize=none build
- name: Compile - name: Compile
run: meson compile -C build run: meson compile -C build
- name: Run Tests - name: Run Tests

View File

@ -3,7 +3,7 @@ project('rtengine', ['c', 'cpp'],
'b_sanitize=none', 'b_sanitize=none',
'c_std=c17', 'c_std=c17',
'cpp_std=c++20', 'cpp_std=c++20',
'warning_level=3', 'warning_level=2',
'werror=true', 'werror=true',
'b_vscrt=static_from_buildtype', 'b_vscrt=static_from_buildtype',
'default_library=static', 'default_library=static',
@ -51,6 +51,18 @@ if host_machine.system() == 'linux'
add_project_arguments(['-D_GNU_SOURCE'], language : ['c', 'cpp']) add_project_arguments(['-D_GNU_SOURCE'], language : ['c', 'cpp'])
endif endif
# Handle Linux to Windows cross compilation.
# By default, mingw does not find its own windows headers...
if build_machine.system() == 'linux' and host_machine.system() == 'windows'
message('Adding /usr/share/mingw-w64/include to the project include path.')
add_project_arguments(['-isystem/usr/share/mingw-w64/include',
'-DRT_CROSS_LINUX_WINDOWS',
'-D_WIN32_WINNT=0x600'],
language: ['c', 'cpp'],
native: false)
endif
fs = import('fs') fs = import('fs')
# Gather dependencies # Gather dependencies
@ -99,7 +111,7 @@ else
endif endif
# Unit/Integration test driver # Unit/Integration test driver
# subdir('tests') subdir('tests')
# Declare dependencies, to enable using the engine as a subproject # Declare dependencies, to enable using the engine as a subproject
engine_dep = declare_dependency(link_with : engine_link_libs, engine_dep = declare_dependency(link_with : engine_link_libs,
@ -120,3 +132,14 @@ if get_option('game_as_subdir')
depends : engine_libs) depends : engine_libs)
endforeach endforeach
endif endif
# For Cross builds, we need libgcc from mingw
if build_machine.system() == 'linux' and host_machine.system() == 'windows'
custom_target('copy libgcc',
input : '/usr/lib/gcc/x86_64-w64-mingw32/10-win32/libgcc_s_seh-1.dll',
output : 'libgcc_s_seh-1.dll',
command : [copy_util, '@INPUT@', '@OUTPUT@'],
build_by_default : true)
endif

View File

@ -5,3 +5,4 @@ option('enable_dxc_shader_compiler', type : 'boolean', value : true, description
option('enable_dx11_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dx11-bases shader compiler.') option('enable_dx11_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dx11-bases shader compiler.')
option('game_as_subdir', type : 'boolean', value : false, description : 'If true, adds the directory "src/game" to the build.') option('game_as_subdir', type : 'boolean', value : false, description : 'If true, adds the directory "src/game" to the build.')
option('build_dx11', type : 'boolean', value : true, description : 'Enables/disables the build of the dx11 renderer.') option('build_dx11', type : 'boolean', value : true, description : 'Enables/disables the build of the dx11 renderer.')
option('build_experiments', type : 'boolean', value : false, description : 'Enables/disables building the experiments in src/experimental.')

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
file="linux_dxc_2023_08_14.x86_64.tar.gz" file="linux_dxc_2023_08_14.x86_64.tar.gz"
if [! -d contrib]; then if [ ! -d contrib ]; then
echo "Could not find 'contrib'. Make sure to run this script from the projects root directory." echo "Could not find 'contrib'. Make sure to run this script from the projects root directory."
exit 1; exit 1;
fi fi

2
scripts/download_dxc_cross.sh Normal file → Executable file
View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
file="dxc_2023_08_14.zip" file="dxc_2023_08_14.zip"
if [! -d contrib]; then if [ ! -d contrib ]; then
echo "Could not find 'contrib'. Make sure to run this script from the projects root directory." echo "Could not find 'contrib'. Make sure to run this script from the projects root directory."
exit 1; exit 1;
fi fi

32
scripts/download_shaderc.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/bash
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Downloads shaderc from github into contrib/
#
# Last changed: 24/11/23 (DD/MM/YY)
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SHADERC_VER=v2023.7
SHADERC_REPO=https://github.com/google/shaderc.git
# Check if we are beeing run from scripts/ or from root
if [ ! -f meson.build ]; then
cd ..
fi
git clone --quiet $SHADERC_REPO contrib/shaderc
pushd contrib/shaderc
git checkout --quiet $SHADERC_VER
python3 ./utils/git-sync-deps
rmdir -rf .git
mkdir build-linux
pushd build-linux
cmake ..
cmake --build . --config Release
popd
popd

View File

@ -15,7 +15,7 @@ RT_CVAR_I(rt_WindowHeight, "Window height. Default: 768", 768);
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
static LRESULT CALLBACK win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static LRESULT CALLBACK win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) { switch (uMsg) {
@ -100,7 +100,7 @@ RT_DLLEXPORT int rtWin32Entry(HINSTANCE hInstance,
{ {
RECT r; RECT r;
GetClientRect(wnd, &r); GetClientRect(wnd, &r);
window_width = r.right; window_width = r.right;
window_height = r.bottom; window_height = r.bottom;
} }
rt_renderer_init_info renderer_info = {.hWnd = wnd, rt_renderer_init_info renderer_info = {.hWnd = wnd,

View File

@ -1,11 +1,17 @@
#ifdef _WIN32 #ifdef _WIN32
// Required by dxcapi.h, does not work with WIN32_LEAN_AND_MEAN // Required by dxcapi.h, does not work with WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
#endif #endif
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wattributes"
#endif #endif
#ifdef RT_CROSS_LINUX_WINDOWS
#include <runtime/cross_sal.h>
#endif
#include <dxcapi.h> #include <dxcapi.h>
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop

View File

@ -5,4 +5,6 @@ subdir('app_framework')
subdir('renderer/common') subdir('renderer/common')
subdir('renderer/dx11') subdir('renderer/dx11')
subdir('experimental') if get_option('build_experiments')
subdir('experimental')
endif

View File

@ -4,7 +4,7 @@
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
void Win32ErrorToString(DWORD last_error, char *out, int bufsize); void Win32ErrorToString(DWORD last_error, char *out, int bufsize);

View File

@ -1,9 +1,9 @@
#include "runtime.h"
#include "config.h" #include "config.h"
#include "runtime.h"
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
#endif #endif
#include <stdio.h> #include <stdio.h>
@ -29,7 +29,6 @@ RT_DLLEXPORT int rtAssertHandler(const char *expr, const char *msg, const char *
line); line);
outmessage[511] = '\0'; outmessage[511] = '\0';
DWORD action = MessageBoxA(NULL, outmessage, "Assertion Failed", MB_YESNOCANCEL | MB_ICONERROR); DWORD action = MessageBoxA(NULL, outmessage, "Assertion Failed", MB_YESNOCANCEL | MB_ICONERROR);
if (action == IDYES) { if (action == IDYES) {
return ASSERT_HANDLER_DBGBREAK; return ASSERT_HANDLER_DBGBREAK;

17
src/runtime/cross_sal.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef RT_CROSS_SAL_H
#define RT_CROSS_SAL_H
/* mingw-w64 seems to miss some SAL annotations that are used by dxc etc.
* This header adds these.
*/
#ifndef RT_CROSS_LINUX_WINDOWS
#pragma warning Are you sure that you want to include this file ?
#endif
#define _Maybenull_
#define _In_opt_count_(n)
#define _In_bytecount_(n)
#define _In_count_(n)
#endif

View File

@ -2,7 +2,7 @@
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
RT_DLLEXPORT rt_dynlib rtOpenCallerLib(void) { RT_DLLEXPORT rt_dynlib rtOpenCallerLib(void) {
return (rt_dynlib)GetModuleHandleW(NULL); return (rt_dynlib)GetModuleHandleW(NULL);

View File

@ -6,7 +6,7 @@
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
#define DbgBreak DebugBreak() #define DbgBreak DebugBreak()
#elif defined(__GNUC__) #elif defined(__GNUC__)

View File

@ -5,7 +5,7 @@
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
struct rt_scandir_handle_s { struct rt_scandir_handle_s {
HANDLE handle; HANDLE handle;

View File

@ -15,6 +15,7 @@ runtime_lib = library('rt',
'buffer_manager.h', 'buffer_manager.h',
'compression.h', 'compression.h',
'config.h', 'config.h',
'cross_sal.h',
'ds.h', 'ds.h',
'dynamic_libs.h', 'dynamic_libs.h',
'file_tab.h', 'file_tab.h',

View File

@ -1,16 +1,16 @@
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#define NOMINMAX #define NOMINMAX
#include <Windows.h>
#include <unknwn.h> #include <unknwn.h>
#include <windows.h>
#endif #endif
/* C standard library*/ /* C standard library*/
#include <limits.h>
#include <math.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h>
#include <math.h>
/* Runtime */ /* Runtime */
#include "runtime/runtime.h" #include "runtime/runtime.h"

View File

@ -10,17 +10,28 @@
#endif #endif
#if ENABLE_STB_SPRINTF #if ENABLE_STB_SPRINTF
#if defined(_MSC_VER)
#pragma warning(push, 0) #pragma warning(push, 0)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif
#define STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION
#define STB_SPRINTF_STATIC #define STB_SPRINTF_STATIC
#include <stb_sprintf.h> #include <stb_sprintf.h>
#if defined(_MSC_VER)
#pragma warning(pop) #pragma warning(pop)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#else #else
#include <stdio.h> #include <stdio.h>
#endif #endif
RT_DLLEXPORT int rtSPrint(char *dest, size_t n, const char *fmt, ...) RT_DLLEXPORT int rtSPrint(char *dest, size_t n, const char *fmt, ...) {
{
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
#if ENABLE_STB_SPRINTF #if ENABLE_STB_SPRINTF
@ -34,8 +45,7 @@ RT_DLLEXPORT int rtSPrint(char *dest, size_t n, const char *fmt, ...)
return r; return r;
} }
RT_DLLEXPORT int rtVSPrint(char *dest, size_t n, const char *fmt, va_list ap) RT_DLLEXPORT int rtVSPrint(char *dest, size_t n, const char *fmt, va_list ap) {
{
#if ENABLE_STB_SPRINTF #if ENABLE_STB_SPRINTF
return stbsp_vsnprintf(dest, (int)n, fmt, ap); return stbsp_vsnprintf(dest, (int)n, fmt, ap);
#else #else

View File

@ -4,7 +4,7 @@
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
#elif defined(__linux__) #elif defined(__linux__)
#include <uchar.h> #include <uchar.h>

View File

@ -68,7 +68,8 @@ RT_DLLEXPORT void rtWaitOnConditionVar(rt_condition_var *var) {
#elif defined(_WIN32) #elif defined(_WIN32)
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
struct rt_condition_var_s { struct rt_condition_var_s {
CRITICAL_SECTION critical_section; CRITICAL_SECTION critical_section;
CONDITION_VARIABLE cond; CONDITION_VARIABLE cond;

View File

@ -3,7 +3,7 @@
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
struct rt_mutex_s { struct rt_mutex_s {
HANDLE handle; HANDLE handle;
@ -92,7 +92,7 @@ RT_DLLEXPORT bool rtUnlockMutex(rt_mutex *mutex) {
return false; return false;
} }
mutex->owner = 0; mutex->owner = 0;
bool result = ReleaseMutex(mutex->handle) != 0; bool result = ReleaseMutex(mutex->handle) != 0;
if (!result) if (!result)
mutex->owner = caller; mutex->owner = caller;
return result; return result;

View File

@ -4,7 +4,7 @@
#if defined(_WIN32) #if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
struct rt_thread_s { struct rt_thread_s {
HANDLE handle; HANDLE handle;
@ -83,9 +83,11 @@ RT_DLLEXPORT rt_thread *rtSpawnThread(rt_thread_entry_fn *entry, void *param, co
thrd = NULL; thrd = NULL;
} }
#ifndef RT_CROSS_LINUX_WINDOWS
WCHAR wname[64]; WCHAR wname[64];
if (thrd && name && rtUTF8ToWStr(name, wname, sizeof(wname)) == RT_SUCCESS) if (thrd && name && rtUTF8ToWStr(name, wname, sizeof(wname)) == RT_SUCCESS)
SetThreadDescription(thrd->handle, wname); SetThreadDescription(thrd->handle, wname);
#endif
} else { } else {
rtReportError("core", "Ran out of thread objects"); rtReportError("core", "Ran out of thread objects");

View File

@ -2,7 +2,7 @@
#if defined(_WIN32) #if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
static uint64_t _QPC_freq = 0u; static uint64_t _QPC_freq = 0u;
@ -11,11 +11,12 @@ rt_result InitTiming(void) {
if (!QueryPerformanceFrequency(&qpc_freq)) { if (!QueryPerformanceFrequency(&qpc_freq)) {
return RT_UNKNOWN_ERROR; return RT_UNKNOWN_ERROR;
} }
_QPC_freq = (uint64_t)qpc_freq.QuadPart; _QPC_freq = (uint64_t)qpc_freq.QuadPart;
double resolution = 1e6 * 1.0 / (double)_QPC_freq; double resolution = 1e6 * 1.0 / (double)_QPC_freq;
rtLog("TIMING", rtLog("TIMING",
"QPC Frequency: %llu ticks per second Resolution: %.2lf us", "QPC Frequency: %llu ticks per second Resolution: %.2lf us",
_QPC_freq, resolution); _QPC_freq,
resolution);
return RT_SUCCESS; return RT_SUCCESS;
} }
@ -23,7 +24,7 @@ rt_result InitTiming(void) {
RT_DLLEXPORT rt_timestamp rtTimeNow(void) { RT_DLLEXPORT rt_timestamp rtTimeNow(void) {
LARGE_INTEGER qpc; LARGE_INTEGER qpc;
QueryPerformanceCounter(&qpc); QueryPerformanceCounter(&qpc);
return (rt_timestamp){.ticks = qpc.QuadPart, .ticks_per_second = _QPC_freq }; return (rt_timestamp){.ticks = qpc.QuadPart, .ticks_per_second = _QPC_freq};
} }
RT_DLLEXPORT rt_time_delta rtTimeBetween(rt_timestamp a, rt_timestamp b) { RT_DLLEXPORT rt_time_delta rtTimeBetween(rt_timestamp a, rt_timestamp b) {

View File

@ -1,7 +1,4 @@
test_link_libs = [runtime_lib] test_link_libs = [runtime_lib]
if get_option('default_library') == 'static'
test_link_libs += null_renderer_lib
endif
rttest_exe = executable('rttest', rttest_exe = executable('rttest',
'rttest.c', 'rttest.c',

View File

@ -1,3 +1,4 @@
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include "runtime/config.h" #include "runtime/config.h"
@ -5,12 +6,6 @@
#include "runtime/mem_arena.h" #include "runtime/mem_arena.h"
#include "runtime/runtime.h" #include "runtime/runtime.h"
#include "gfx/gfx.h"
#include "gfx/render_list.h"
#include "gfx/renderer_api.h"
extern rt_cvar rt_Renderer;
/* Check basic relative pointer behaviour */ /* Check basic relative pointer behaviour */
static rt_result RelPtrTest(void) { static rt_result RelPtrTest(void) {
char buf[sizeof(rt_relptr) + sizeof(unsigned int)]; char buf[sizeof(rt_relptr) + sizeof(unsigned int)];
@ -46,6 +41,7 @@ static rt_result NegRelPtrTest(void) {
return RT_SUCCESS; return RT_SUCCESS;
} }
#if 0
static rt_result SetupRenderListFixture(void) { static rt_result SetupRenderListFixture(void) {
rt_result res = rtInitRuntime(); rt_result res = rtInitRuntime();
if (res != RT_SUCCESS) if (res != RT_SUCCESS)
@ -120,6 +116,7 @@ static rt_result PushLongRenderList(void) {
} }
return RT_SUCCESS; return RT_SUCCESS;
} }
#endif
static rt_result HashTableBasics(void) { static rt_result HashTableBasics(void) {
{ {
@ -140,14 +137,14 @@ static rt_result HashTableBasics(void) {
if (!arena_res.ok) if (!arena_res.ok)
return RT_OUT_OF_MEMORY; return RT_OUT_OF_MEMORY;
rt_arena arena = arena_res.arena; rt_arena arena = arena_res.arena;
void *mem = rtArenaPush(&arena, RT_HASH_TABLE_MEMORY_REQUIRED(64)); void *mem = rtArenaPush(&arena, RT_HASH_TABLE_MEMORY_REQUIRED(64));
if (!mem) if (!mem)
return RT_OUT_OF_MEMORY; return RT_OUT_OF_MEMORY;
rt_hashtable ht = rtCreateHashtable(64, mem, rtHashtableGrowMemoryFromArena, &arena); rt_hashtable ht = rtCreateHashtable(64, mem, rtHashtableGrowMemoryFromArena, &arena);
for (uint64_t i = 0; i < 64; ++i) { for (uint64_t i = 0; i < 64; ++i) {
if (rtHashtableInsert(&ht, 256+i, i) != RT_SUCCESS) if (rtHashtableInsert(&ht, 256 + i, i) != RT_SUCCESS)
return RT_UNKNOWN_ERROR; return RT_UNKNOWN_ERROR;
uint64_t found = rtHashtableLookup(&ht, 256+i, UINT64_MAX); uint64_t found = rtHashtableLookup(&ht, 256 + i, UINT64_MAX);
if (found != i) if (found != i)
return RT_INVALID_VALUE; return RT_INVALID_VALUE;
} }
@ -188,8 +185,8 @@ typedef struct {
/* X-Macro to create named fixtures */ /* X-Macro to create named fixtures */
/* Add more fixtures here*/ /* Add more fixtures here*/
#define TEST_FIXTURE_LIST \ #define TEST_FIXTURE_LIST
TEST_FIXTURE(render_list_fixture, SetupRenderListFixture, TeardownRenderListFixture) // TEST_FIXTURE(render_list_fixture, SetupRenderListFixture, TeardownRenderListFixture)
#define TEST_FIXTURE(n, setup_fn, teardown_fn) \ #define TEST_FIXTURE(n, setup_fn, teardown_fn) \
rt_test_fixture n = {.name = #n, \ rt_test_fixture n = {.name = #n, \
@ -205,8 +202,8 @@ static rt_test_fixture *_test_fixtures[] = {TEST_FIXTURE_LIST};
static rt_test_case _test_cases[] = {TEST_CASE(RelPtrTest), static rt_test_case _test_cases[] = {TEST_CASE(RelPtrTest),
TEST_CASE(NegRelPtrTest), TEST_CASE(NegRelPtrTest),
TEST_CASE_FIXTURE(PushRenderList, render_list_fixture), /*TEST_CASE_FIXTURE(PushRenderList, render_list_fixture),
TEST_CASE_FIXTURE(PushLongRenderList, render_list_fixture), TEST_CASE_FIXTURE(PushLongRenderList, render_list_fixture),*/
TEST_CASE(HashTableBasics)}; TEST_CASE(HashTableBasics)};
int main() { int main() {
@ -241,8 +238,10 @@ int main() {
} }
} }
/* Teardown fixtures */ /* Teardown fixtures.
for (size_t i = 0; i < RT_ARRAY_COUNT(_test_fixtures); ++i) { * The +1 is necessary to avoid comparing i=0 < 0, which causes a compile
* error */
for (size_t i = 0; (i + 1) < (RT_ARRAY_COUNT(_test_fixtures) + 1); ++i) {
if (_test_fixtures[i]->is_initialized) { if (_test_fixtures[i]->is_initialized) {
printf("[TEARDOWN %s] ... ", _test_fixtures[i]->name); printf("[TEARDOWN %s] ... ", _test_fixtures[i]->name);
_test_fixtures[i]->teardown(); _test_fixtures[i]->teardown();