diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb9a056..7c68046 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: run: >- docker build -f ${{ matrix.dockerfile }} - --build-arg build_type=${{ matrix.build_type }} + --build-arg BUILD_TYPE=${{ matrix.build_type }} --target build -t ${{ matrix.image }} . @@ -59,7 +59,7 @@ jobs: rm -rf dist docker build \ -f ${{ matrix.dockerfile }} \ - --build-arg build_type=${{ matrix.build_type }} \ + --build-arg BUILD_TYPE=${{ matrix.build_type }} \ --target export \ --output dist \ . diff --git a/AGENTS.md b/AGENTS.md index 10962ab..42600d5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,7 +6,7 @@ - Sample fixtures for exercising the loader live in `test/`. ## Build, Test, and Development Commands -- `cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_TESTING=ON` configures a 32-bit toolchain; ensure multilib packages are present. +- `cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON` configures a 32-bit toolchain; ensure multilib packages are present. - `cmake --build build --target wibo` compiles the program and tests. - `./build/wibo /path/to/program.exe` runs a Windows binary. Use `WIBO_DEBUG=1` (or `--debug`/`-D`) for verbose logging. Use `--chdir`/`-C` to set the working directory. - `cmake -B build -DBUILD_TESTING=ON` + `ctest --test-dir build --output-on-failure` runs the self-checking WinAPI fixtures (requires `i686-w64-mingw32-gcc` and `i686-w64-mingw32-windres`). @@ -25,7 +25,7 @@ - Add `DEBUG_LOG` calls to trace execution and parameter values; these are invaluable when diagnosing issues with real-world binaries. ## Testing Guidelines -- Fixture tests live in `test/` and are compiled automatically with `i686-w64-mingw32-gcc` when `BUILD_TESTING` is enabled. +- Fixture tests live in `test/` and are compiled automatically with `i686-w64-mingw32-gcc`. - Keep new repros small and self-contained (`test_.c`). - All fixtures must self-assert; use `test_assert.h` helpers so `ctest` fails on mismatched WinAPI behaviour. - Update `CMakeLists.txt` to add new fixture sources. diff --git a/CMakeLists.txt b/CMakeLists.txt index 681ac64..f95f2df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,5 @@ cmake_minimum_required(VERSION 3.13) -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Debug" CACHE STRING - "Build type options: Debug Release RelWithDebInfo MinSizeRel" FORCE) -endif() - set(CMAKE_C_FLAGS_INIT "-m32") set(CMAKE_CXX_FLAGS_INIT "-m32") set(CMAKE_EXE_LINKER_FLAGS_INIT "-m32") @@ -12,15 +7,35 @@ set(CMAKE_SHARED_LINKER_FLAGS_INIT "-m32") project(wibo LANGUAGES C CXX) -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +option(WIBO_ENABLE_FIXTURE_TESTS "Enable Win32 fixture tests (requires i686-w64-mingw32)" ON) +option(WIBO_ENABLE_LIBURING "Enable liburing for asynchronous I/O" OFF) +set(WIBO_ENABLE_LTO "AUTO" CACHE STRING "Enable link-time optimization (LTO)") +set_property(CACHE WIBO_ENABLE_LTO PROPERTY STRINGS "AUTO" "ON" "OFF") -set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-pie -no-pie -D_LARGEFILE64_SOURCE") +if (WIBO_ENABLE_LTO STREQUAL "AUTO") + if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") + include(CheckIPOSupported) + check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error) + if (ipo_supported) + message(STATUS "Enabling LTO") + set(WIBO_ENABLE_LTO ON) + else() + message(STATUS "LTO not supported: ${ipo_error}") + set(WIBO_ENABLE_LTO OFF) + endif() + else() + message(STATUS "Disabling LTO") + set(WIBO_ENABLE_LTO OFF) + endif() +elseif (NOT (WIBO_ENABLE_LTO STREQUAL "ON" OR WIBO_ENABLE_LTO STREQUAL "OFF")) + message(FATAL_ERROR "WIBO_ENABLE_LTO must be ON, OFF, or AUTO") +endif() +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ${WIBO_ENABLE_LTO}) -find_package(Filesystem REQUIRED) - -# Disable mimalloc tests +# Fetch and configure mimalloc +set(MI_BUILD_SHARED OFF CACHE BOOL "Build shared library" FORCE) +set(MI_BUILD_STATIC OFF CACHE BOOL "Build static library" FORCE) +set(MI_BUILD_OBJECT ON CACHE BOOL "Build object library" FORCE) set(MI_BUILD_TESTS OFF CACHE BOOL "Build test executables" FORCE) include(FetchContent) @@ -31,35 +46,43 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(mimalloc) -FetchContent_Declare( - liburing - GIT_REPOSITORY https://github.com/axboe/liburing.git - GIT_TAG liburing-2.4 -) -FetchContent_MakeAvailable(liburing) +# Disable `note: the alignment of '_Atomic long long int' fields changed in GCC 11.1` +target_compile_options(mimalloc-obj PRIVATE -Wno-psabi) -set(LIBURING_COMPAT ${liburing_SOURCE_DIR}/src/include/liburing/compat.h) -add_custom_command( - OUTPUT ${LIBURING_COMPAT} - COMMAND ${CMAKE_COMMAND} -E env - CC=${CMAKE_C_COMPILER} - AR=${CMAKE_AR} - RANLIB=${CMAKE_RANLIB} - ./configure --cc=${CMAKE_C_COMPILER} - WORKING_DIRECTORY ${liburing_SOURCE_DIR} - COMMENT "Running liburing configure" - VERBATIM -) -add_custom_target(liburing_configure DEPENDS ${LIBURING_COMPAT}) -add_library(liburing STATIC - ${liburing_SOURCE_DIR}/src/queue.c - ${liburing_SOURCE_DIR}/src/register.c - ${liburing_SOURCE_DIR}/src/setup.c - ${liburing_SOURCE_DIR}/src/syscall.c - ${liburing_SOURCE_DIR}/src/version.c) -add_dependencies(liburing liburing_configure) -target_include_directories(liburing PUBLIC ${liburing_SOURCE_DIR}/src/include) -target_compile_definitions(liburing PRIVATE _GNU_SOURCE) +if (WIBO_ENABLE_LIBURING) + FetchContent_Declare( + liburing + GIT_REPOSITORY https://github.com/axboe/liburing.git + GIT_TAG e907d6a342e80b70874f93abd440b92b8a40b7bc # liburing-2.12 + ) + FetchContent_MakeAvailable(liburing) + + add_custom_command( + OUTPUT ${liburing_SOURCE_DIR}/config-host.h + ${liburing_SOURCE_DIR}/src/include/liburing/compat.h + COMMAND ${CMAKE_COMMAND} -E env + CC=${CMAKE_C_COMPILER} + CXX=${CMAKE_CXX_COMPILER} + ./configure --prefix=${liburing_BINARY_DIR} + WORKING_DIRECTORY ${liburing_SOURCE_DIR} + DEPENDS ${liburing_SOURCE_DIR}/configure + COMMENT "Running liburing configure" + VERBATIM + ) + add_library(liburing STATIC + ${liburing_SOURCE_DIR}/config-host.h + ${liburing_SOURCE_DIR}/src/nolibc.c + ${liburing_SOURCE_DIR}/src/queue.c + ${liburing_SOURCE_DIR}/src/register.c + ${liburing_SOURCE_DIR}/src/setup.c + ${liburing_SOURCE_DIR}/src/syscall.c + ${liburing_SOURCE_DIR}/src/version.c + ${liburing_SOURCE_DIR}/src/include/liburing/compat.h) + target_compile_definitions(liburing PRIVATE _GNU_SOURCE _FILE_OFFSET_BITS=64 _TIME_BITS=64) + target_compile_options(liburing PRIVATE -include config-host.h) + target_include_directories(liburing PUBLIC ${liburing_SOURCE_DIR}/src/include) + target_include_directories(liburing PRIVATE ${liburing_SOURCE_DIR}) +endif() add_executable(wibo dll/advapi32.cpp @@ -116,14 +139,24 @@ add_executable(wibo src/resources.cpp src/strutil.cpp ) -target_include_directories(wibo PRIVATE dll src) +target_compile_definitions(wibo PRIVATE _GNU_SOURCE _FILE_OFFSET_BITS=64 _TIME_BITS=64) target_compile_features(wibo PRIVATE cxx_std_20) -target_link_libraries(wibo PRIVATE std::filesystem mimalloc-static liburing) +target_compile_options(wibo PRIVATE -Wall -Wextra -fno-pie -maccumulate-outgoing-args) +target_include_directories(wibo PRIVATE dll src) +target_link_libraries(wibo PRIVATE mimalloc-obj) +target_link_options(wibo PRIVATE -no-pie) +if (WIBO_ENABLE_LIBURING) + target_compile_definitions(wibo PRIVATE WIBO_ENABLE_LIBURING=1) + target_link_libraries(wibo PRIVATE liburing) + target_sources(wibo PRIVATE src/async_io_uring.cpp) +else() + target_compile_definitions(wibo PRIVATE WIBO_ENABLE_LIBURING=0) +endif() install(TARGETS wibo DESTINATION bin) -include(CTest) +if (WIBO_ENABLE_FIXTURE_TESTS) + include(CTest) -if(BUILD_TESTING) find_program(WIBO_MINGW_CC i686-w64-mingw32-gcc) find_program(WIBO_MINGW_WINDRES i686-w64-mingw32-windres) @@ -132,443 +165,105 @@ if(BUILD_TESTING) set(WIBO_HAVE_MINGW_TOOLCHAIN TRUE) endif() - option(WIBO_ENABLE_FIXTURE_TESTS "Build and run Windows fixture binaries through wibo" ${WIBO_HAVE_MINGW_TOOLCHAIN}) + if(NOT WIBO_HAVE_MINGW_TOOLCHAIN) + message(WARNING "MinGW toolchain not found; skipping fixture tests") + else() + set(WIBO_TEST_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}/test) + file(MAKE_DIRECTORY ${WIBO_TEST_BIN_DIR}) - if(WIBO_ENABLE_FIXTURE_TESTS) - if(NOT WIBO_HAVE_MINGW_TOOLCHAIN) - message(WARNING "MinGW toolchain not found; skipping fixture tests") + function(wibo_add_fixture_dll) + set(options) + set(oneValueArgs NAME) + set(multiValueArgs SOURCES COMPILE_OPTIONS DEPENDS) + cmake_parse_arguments(PARSE_ARGV 0 fixture "${options}" "${oneValueArgs}" "${multiValueArgs}") + + set(fixture_OUTPUT ${WIBO_TEST_BIN_DIR}/${fixture_NAME}.dll) + add_custom_command( + OUTPUT ${fixture_OUTPUT} + COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared + -I${CMAKE_CURRENT_SOURCE_DIR}/test + -o ${fixture_OUTPUT} + ${fixture_SOURCES} + ${fixture_COMPILE_OPTIONS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${fixture_SOURCES} ${fixture_DEPENDS}) + list(APPEND WIBO_TEST_FIXTURES ${fixture_OUTPUT}) + set(WIBO_TEST_FIXTURES ${WIBO_TEST_FIXTURES} PARENT_SCOPE) + endfunction(wibo_add_fixture_dll) + + function(wibo_add_fixture_bin) + set(options) + set(oneValueArgs NAME) + set(multiValueArgs SOURCES COMPILE_OPTIONS DEPENDS) + cmake_parse_arguments(PARSE_ARGV 0 fixture "${options}" "${oneValueArgs}" "${multiValueArgs}") + + set(fixture_OUTPUT ${WIBO_TEST_BIN_DIR}/${fixture_NAME}.exe) + add_custom_command( + OUTPUT ${fixture_OUTPUT} + COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 + -I${CMAKE_CURRENT_SOURCE_DIR}/test + -o ${fixture_OUTPUT} + ${fixture_SOURCES} + ${fixture_COMPILE_OPTIONS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${fixture_SOURCES} ${fixture_DEPENDS}) + list(APPEND WIBO_TEST_FIXTURES ${fixture_OUTPUT}) + set(WIBO_TEST_FIXTURES ${WIBO_TEST_FIXTURES} PARENT_SCOPE) + + add_test(NAME wibo.${fixture_NAME} + COMMAND $ ${fixture_OUTPUT}) + set_tests_properties(wibo.${fixture_NAME} PROPERTIES + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test + DEPENDS wibo.build_fixtures) + endfunction(wibo_add_fixture_bin) + + # Define fixture tests + wibo_add_fixture_bin(NAME test_external_dll SOURCES test/test_external_dll.c) + wibo_add_fixture_bin(NAME test_dll_attach_failure SOURCES test/test_dll_attach_failure.c) + wibo_add_fixture_bin(NAME test_thread_notifications SOURCES test/test_thread_notifications.c) + wibo_add_fixture_bin(NAME test_bcrypt SOURCES test/test_bcrypt.c COMPILE_OPTIONS -lbcrypt) + wibo_add_fixture_bin(NAME test_resources SOURCES test/test_resources.c ${WIBO_TEST_BIN_DIR}/test_resources_res.o COMPILE_OPTIONS -lversion) + wibo_add_fixture_bin(NAME test_threading SOURCES test/test_threading.c) + wibo_add_fixture_bin(NAME test_handleapi SOURCES test/test_handleapi.c) + wibo_add_fixture_bin(NAME test_findfile SOURCES test/test_findfile.c) + wibo_add_fixture_bin(NAME test_synchapi SOURCES test/test_synchapi.c) + wibo_add_fixture_bin(NAME test_processes SOURCES test/test_processes.c) + wibo_add_fixture_bin(NAME test_heap SOURCES test/test_heap.c) + wibo_add_fixture_bin(NAME test_actctx SOURCES test/test_actctx.c) + wibo_add_fixture_bin(NAME test_overlapped_io SOURCES test/test_overlapped_io.c) + wibo_add_fixture_bin(NAME test_time SOURCES test/test_time.c) + wibo_add_fixture_bin(NAME test_virtualalloc SOURCES test/test_virtualalloc.c) + wibo_add_fixture_bin(NAME test_virtualquery SOURCES test/test_virtualquery.c) + wibo_add_fixture_bin(NAME test_rtl SOURCES test/test_rtl.c) + wibo_add_fixture_bin(NAME test_ntquery SOURCES test/test_ntquery.c) + wibo_add_fixture_bin(NAME test_ntreadfile SOURCES test/test_ntreadfile.c) + wibo_add_fixture_bin(NAME test_pipe_io SOURCES test/test_pipe_io.c) + wibo_add_fixture_bin(NAME test_sysdir SOURCES test/test_sysdir.c) + + # DLLs for fixture tests + wibo_add_fixture_dll(NAME external_exports SOURCES test/external_exports.c) + wibo_add_fixture_dll(NAME dll_attach_failure SOURCES test/dll_attach_failure.c) + wibo_add_fixture_dll(NAME thread_notifications SOURCES test/thread_notifications.c) + + # Resources for test_resources + add_custom_command( + OUTPUT ${WIBO_TEST_BIN_DIR}/test_resources_res.o + COMMAND ${WIBO_MINGW_WINDRES} + ${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.rc + -O coff -o test_resources_res.o + WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.rc) + + add_custom_target(wibo_test_fixtures DEPENDS ${WIBO_TEST_FIXTURES}) + + if(CMAKE_CONFIGURATION_TYPES) + set(_wibo_fixture_build_command + ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --config $ --target wibo_test_fixtures) else() - set(WIBO_TEST_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}/test) - file(MAKE_DIRECTORY ${WIBO_TEST_BIN_DIR}) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/external_exports.dll - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared - -o external_exports.dll - ${CMAKE_CURRENT_SOURCE_DIR}/test/external_exports.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/external_exports.c) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/dll_attach_failure.dll - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared - -o dll_attach_failure.dll - ${CMAKE_CURRENT_SOURCE_DIR}/test/dll_attach_failure.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/dll_attach_failure.c) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/thread_notifications.dll - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared - -o thread_notifications.dll - ${CMAKE_CURRENT_SOURCE_DIR}/test/thread_notifications.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/thread_notifications.c) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_external_dll.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_external_dll.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_external_dll.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_external_dll.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_dll_attach_failure.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_dll_attach_failure.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_dll_attach_failure.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_dll_attach_failure.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_thread_notifications.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_thread_notifications.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_thread_notifications.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_thread_notifications.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_bcrypt.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_bcrypt.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_bcrypt.c - -lbcrypt - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_bcrypt.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_resources_res.o - COMMAND ${WIBO_MINGW_WINDRES} - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.rc - -O coff -o test_resources_res.o - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.rc) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_resources.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_resources.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.c - test_resources_res.o -lversion - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h - ${WIBO_TEST_BIN_DIR}/test_resources_res.o) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_threading.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_threading.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_threading.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_threading.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_handleapi.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_handleapi.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_handleapi.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_handleapi.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_findfile.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_findfile.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_findfile.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_findfile.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_synchapi.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_synchapi.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_synchapi.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_synchapi.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_processes.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_processes.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_processes.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_processes.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_heap.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_heap.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_heap.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_heap.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_actctx.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_actctx.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_actctx.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_actctx.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_overlapped_io.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_overlapped_io.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_overlapped_io.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_time.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_time.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_time.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_time.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_virtualalloc.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_virtualalloc.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_virtualalloc.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_virtualalloc.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_virtualquery.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_virtualquery.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_virtualquery.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_virtualquery.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_rtl.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_rtl.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_rtl.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_rtl.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_ntquery.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_ntquery.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_ntquery.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_ntquery.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_ntreadfile.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_ntreadfile.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_ntreadfile.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_ntreadfile.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_pipe_io.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_pipe_io.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_pipe_io.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_pipe_io.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_command( - OUTPUT ${WIBO_TEST_BIN_DIR}/test_sysdir.exe - COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 - -I${CMAKE_CURRENT_SOURCE_DIR}/test - -o test_sysdir.exe - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_sysdir.c - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_sysdir.c - ${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h) - - add_custom_target(wibo_test_fixtures - DEPENDS - ${WIBO_TEST_BIN_DIR}/external_exports.dll - ${WIBO_TEST_BIN_DIR}/dll_attach_failure.dll - ${WIBO_TEST_BIN_DIR}/thread_notifications.dll - ${WIBO_TEST_BIN_DIR}/test_external_dll.exe - ${WIBO_TEST_BIN_DIR}/test_dll_attach_failure.exe - ${WIBO_TEST_BIN_DIR}/test_thread_notifications.exe - ${WIBO_TEST_BIN_DIR}/test_bcrypt.exe - ${WIBO_TEST_BIN_DIR}/test_resources.exe - ${WIBO_TEST_BIN_DIR}/test_threading.exe - ${WIBO_TEST_BIN_DIR}/test_handleapi.exe - ${WIBO_TEST_BIN_DIR}/test_findfile.exe - ${WIBO_TEST_BIN_DIR}/test_synchapi.exe - ${WIBO_TEST_BIN_DIR}/test_processes.exe - ${WIBO_TEST_BIN_DIR}/test_heap.exe - ${WIBO_TEST_BIN_DIR}/test_actctx.exe - ${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe - ${WIBO_TEST_BIN_DIR}/test_time.exe - ${WIBO_TEST_BIN_DIR}/test_virtualalloc.exe - ${WIBO_TEST_BIN_DIR}/test_virtualquery.exe - ${WIBO_TEST_BIN_DIR}/test_rtl.exe - ${WIBO_TEST_BIN_DIR}/test_ntquery.exe - ${WIBO_TEST_BIN_DIR}/test_ntreadfile.exe - ${WIBO_TEST_BIN_DIR}/test_pipe_io.exe - ${WIBO_TEST_BIN_DIR}/test_sysdir.exe) - - if(CMAKE_CONFIGURATION_TYPES) - set(_wibo_fixture_build_command - ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --config $ --target wibo_test_fixtures) - else() - set(_wibo_fixture_build_command - ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target wibo_test_fixtures) - endif() - - add_test(NAME wibo.build_fixtures COMMAND ${_wibo_fixture_build_command}) - - add_test(NAME wibo.test_external_dll - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_external_dll.exe) - set_tests_properties(wibo.test_external_dll PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_bcrypt - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_bcrypt.exe) - set_tests_properties(wibo.test_bcrypt PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_resources - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_resources.exe) - set_tests_properties(wibo.test_resources PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_threading - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_threading.exe) - set_tests_properties(wibo.test_threading PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_handleapi - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_handleapi.exe) - set_tests_properties(wibo.test_handleapi PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_findfile - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_findfile.exe) - set_tests_properties(wibo.test_findfile PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_synchapi - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_synchapi.exe) - set_tests_properties(wibo.test_synchapi PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_processes - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_processes.exe) - set_tests_properties(wibo.test_processes PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_heap - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_heap.exe) - set_tests_properties(wibo.test_heap PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_actctx - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_actctx.exe) - set_tests_properties(wibo.test_actctx PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_overlapped_io - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe) - set_tests_properties(wibo.test_overlapped_io PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_time - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_time.exe) - set_tests_properties(wibo.test_time PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_virtualalloc - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_virtualalloc.exe) - set_tests_properties(wibo.test_virtualalloc PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_virtualquery - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_virtualquery.exe) - set_tests_properties(wibo.test_virtualquery PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_rtl - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_rtl.exe) - set_tests_properties(wibo.test_rtl PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_ntquery - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_ntquery.exe) - set_tests_properties(wibo.test_ntquery PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_ntreadfile - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_ntreadfile.exe) - set_tests_properties(wibo.test_ntreadfile PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_pipe_io - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_pipe_io.exe) - set_tests_properties(wibo.test_pipe_io PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_sysdir - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_sysdir.exe) - set_tests_properties(wibo.test_sysdir PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_dll_attach_failure - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_dll_attach_failure.exe) - set_tests_properties(wibo.test_dll_attach_failure PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) - - add_test(NAME wibo.test_thread_notifications - COMMAND $ ${WIBO_TEST_BIN_DIR}/test_thread_notifications.exe) - set_tests_properties(wibo.test_thread_notifications PROPERTIES - WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR} - DEPENDS wibo.build_fixtures) + set(_wibo_fixture_build_command + ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target wibo_test_fixtures) endif() + + add_test(NAME wibo.build_fixtures COMMAND ${_wibo_fixture_build_command}) endif() endif() diff --git a/Dockerfile b/Dockerfile index 476f67c..6d4ae2e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,7 @@ RUN apk add --no-cache \ bash \ binutils \ cmake \ + coreutils \ g++ \ git \ linux-headers \ @@ -19,18 +20,21 @@ WORKDIR /wibo COPY . /wibo # Build type (Release, Debug, RelWithDebInfo, MinSizeRel) -ARG build_type=Release +ARG BUILD_TYPE=Release + +# Enable link-time optimization (LTO) (AUTO, ON, OFF) +ARG ENABLE_LTO=AUTO # Build static binary RUN cmake -S /wibo -B /wibo/build -G Ninja \ - -DCMAKE_BUILD_TYPE="$build_type" \ - -DCMAKE_C_FLAGS="-static" \ - -DCMAKE_CXX_FLAGS="-static" \ - -DBUILD_TESTING=ON \ - -DWIBO_ENABLE_FIXTURE_TESTS=ON \ - -DMI_LIBC_MUSL=ON \ - && cmake --build /wibo/build \ - && ( [ "$build_type" != "Release" ] || strip -g /wibo/build/wibo ) + -DCMAKE_BUILD_TYPE:STRING="$BUILD_TYPE" \ + -DCMAKE_C_FLAGS:STRING="-static" \ + -DCMAKE_CXX_FLAGS:STRING="-static" \ + -DMI_LIBC_MUSL:BOOL=ON \ + -DWIBO_ENABLE_LIBURING:BOOL=ON \ + -DWIBO_ENABLE_LTO:STRING="$ENABLE_LTO" \ + && cmake --build /wibo/build --verbose \ + && ( [ "$BUILD_TYPE" != "Release" ] || strip -g /wibo/build/wibo ) # Export binary (usage: docker build --target export --output build .) FROM scratch AS export diff --git a/Dockerfile.ubuntu b/Dockerfile.ubuntu index 09d0a8c..a1f6cf9 100644 --- a/Dockerfile.ubuntu +++ b/Dockerfile.ubuntu @@ -25,14 +25,17 @@ WORKDIR /wibo COPY . /wibo # Build type (Release, Debug, RelWithDebInfo, MinSizeRel) -ARG build_type=Release +ARG BUILD_TYPE=Release + +# Enable link-time optimization (LTO) (AUTO, ON, OFF) +ARG ENABLE_LTO=AUTO RUN cmake -S /wibo -B /wibo/build -G Ninja \ - -DCMAKE_BUILD_TYPE="$build_type" \ - -DBUILD_TESTING=ON \ - -DWIBO_ENABLE_FIXTURE_TESTS=ON \ - && cmake --build /wibo/build \ - && ( [ "$build_type" != "Release" ] || strip -g /wibo/build/wibo ) + -DCMAKE_BUILD_TYPE:STRING="$BUILD_TYPE" \ + -DWIBO_ENABLE_LIBURING:BOOL=ON \ + -DWIBO_ENABLE_LTO:STRING="$ENABLE_LTO" \ + && cmake --build /wibo/build --verbose \ + && ( [ "$BUILD_TYPE" != "Release" ] || strip -g /wibo/build/wibo ) # Export binary (usage: docker build -f Dockerfile.ubuntu --target export --output dist .) FROM scratch AS export diff --git a/README.md b/README.md index 3592004..894d7ab 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A minimal, low-fuss wrapper that can run simple command-line 32-bit Windows bina ## Building ```sh -cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_TESTING=ON +cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON cmake --build build ``` diff --git a/cmake/FindFilesystem.cmake b/cmake/FindFilesystem.cmake deleted file mode 100644 index a152e52..0000000 --- a/cmake/FindFilesystem.cmake +++ /dev/null @@ -1,247 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -#[=======================================================================[.rst: - -FindFilesystem -############## - -This module supports the C++17 standard library's filesystem utilities. Use the -:imp-target:`std::filesystem` imported target to - -Options -******* - -The ``COMPONENTS`` argument to this module supports the following values: - -.. find-component:: Experimental - :name: fs.Experimental - - Allows the module to find the "experimental" Filesystem TS version of the - Filesystem library. This is the library that should be used with the - ``std::experimental::filesystem`` namespace. - -.. find-component:: Final - :name: fs.Final - - Finds the final C++17 standard version of the filesystem library. - -If no components are provided, behaves as if the -:find-component:`fs.Final` component was specified. - -If both :find-component:`fs.Experimental` and :find-component:`fs.Final` are -provided, first looks for ``Final``, and falls back to ``Experimental`` in case -of failure. If ``Final`` is found, :imp-target:`std::filesystem` and all -:ref:`variables ` will refer to the ``Final`` version. - - -Imported Targets -**************** - -.. imp-target:: std::filesystem - - The ``std::filesystem`` imported target is defined when any requested - version of the C++ filesystem library has been found, whether it is - *Experimental* or *Final*. - - If no version of the filesystem library is available, this target will not - be defined. - - .. note:: - This target has ``cxx_std_17`` as an ``INTERFACE`` - :ref:`compile language standard feature `. Linking - to this target will automatically enable C++17 if no later standard - version is already required on the linking target. - - -.. _fs.variables: - -Variables -********* - -.. variable:: CXX_FILESYSTEM_IS_EXPERIMENTAL - - Set to ``TRUE`` when the :find-component:`fs.Experimental` version of C++ - filesystem library was found, otherwise ``FALSE``. - -.. variable:: CXX_FILESYSTEM_HAVE_FS - - Set to ``TRUE`` when a filesystem header was found. - -.. variable:: CXX_FILESYSTEM_HEADER - - Set to either ``filesystem`` or ``experimental/filesystem`` depending on - whether :find-component:`fs.Final` or :find-component:`fs.Experimental` was - found. - -.. variable:: CXX_FILESYSTEM_NAMESPACE - - Set to either ``std::filesystem`` or ``std::experimental::filesystem`` - depending on whether :find-component:`fs.Final` or - :find-component:`fs.Experimental` was found. - - -Examples -******** - -Using `find_package(Filesystem)` with no component arguments: - -.. code-block:: cmake - - find_package(Filesystem REQUIRED) - - add_executable(my-program main.cpp) - target_link_libraries(my-program PRIVATE std::filesystem) - - -#]=======================================================================] - - -if(TARGET std::filesystem) - # This module has already been processed. Don't do it again. - return() -endif() - -cmake_minimum_required(VERSION 3.10) - -include(CMakePushCheckState) -include(CheckIncludeFileCXX) - -# If we're not cross-compiling, try to run test executables. -# Otherwise, assume that compile + link is a sufficient check. -if(CMAKE_CROSSCOMPILING) - include(CheckCXXSourceCompiles) - macro(_cmcm_check_cxx_source code var) - check_cxx_source_compiles("${code}" ${var}) - endmacro() -else() - include(CheckCXXSourceRuns) - macro(_cmcm_check_cxx_source code var) - check_cxx_source_runs("${code}" ${var}) - endmacro() -endif() - -cmake_push_check_state() - -set(CMAKE_REQUIRED_QUIET ${Filesystem_FIND_QUIETLY}) - -# All of our tests required C++17 or later -set(CMAKE_CXX_STANDARD 17) - -# Normalize and check the component list we were given -set(want_components ${Filesystem_FIND_COMPONENTS}) -if(Filesystem_FIND_COMPONENTS STREQUAL "") - set(want_components Final) -endif() - -# Warn on any unrecognized components -set(extra_components ${want_components}) -list(REMOVE_ITEM extra_components Final Experimental) -foreach(component IN LISTS extra_components) - message(WARNING "Extraneous find_package component for Filesystem: ${component}") -endforeach() - -# Detect which of Experimental and Final we should look for -set(find_experimental TRUE) -set(find_final TRUE) -if(NOT "Final" IN_LIST want_components) - set(find_final FALSE) -endif() -if(NOT "Experimental" IN_LIST want_components) - set(find_experimental FALSE) -endif() - -if(find_final) - check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER) - mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER) - if(_CXX_FILESYSTEM_HAVE_HEADER) - # We found the non-experimental header. Don't bother looking for the - # experimental one. - set(find_experimental FALSE) - endif() -else() - set(_CXX_FILESYSTEM_HAVE_HEADER FALSE) -endif() - -if(find_experimental) - check_include_file_cxx("experimental/filesystem" _CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER) - mark_as_advanced(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER) -else() - set(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER FALSE) -endif() - -if(_CXX_FILESYSTEM_HAVE_HEADER) - set(_have_fs TRUE) - set(_fs_header filesystem) - set(_fs_namespace std::filesystem) - set(_is_experimental FALSE) -elseif(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER) - set(_have_fs TRUE) - set(_fs_header experimental/filesystem) - set(_fs_namespace std::experimental::filesystem) - set(_is_experimental TRUE) -else() - set(_have_fs FALSE) -endif() - -set(CXX_FILESYSTEM_HAVE_FS ${_have_fs} CACHE BOOL "TRUE if we have the C++ filesystem headers") -set(CXX_FILESYSTEM_HEADER ${_fs_header} CACHE STRING "The header that should be included to obtain the filesystem APIs") -set(CXX_FILESYSTEM_NAMESPACE ${_fs_namespace} CACHE STRING "The C++ namespace that contains the filesystem APIs") -set(CXX_FILESYSTEM_IS_EXPERIMENTAL ${_is_experimental} CACHE BOOL "TRUE if the C++ filesystem library is the experimental version") - -set(_found FALSE) - -if(CXX_FILESYSTEM_HAVE_FS) - # We have some filesystem library available. Do link checks - string(CONFIGURE [[ - #include - #include <@CXX_FILESYSTEM_HEADER@> - - int main() { - auto cwd = @CXX_FILESYSTEM_NAMESPACE@::current_path(); - printf("%s", cwd.c_str()); - return EXIT_SUCCESS; - } - ]] code @ONLY) - - # Check a simple filesystem program without any linker flags - _cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED) - - set(can_link ${CXX_FILESYSTEM_NO_LINK_NEEDED}) - - if(NOT CXX_FILESYSTEM_NO_LINK_NEEDED) - set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES}) - # Add the libstdc++ flag - set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs) - _cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED) - set(can_link ${CXX_FILESYSTEM_STDCPPFS_NEEDED}) - if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED) - # Try the libc++ flag - set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs) - _cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_CPPFS_NEEDED) - set(can_link ${CXX_FILESYSTEM_CPPFS_NEEDED}) - endif() - endif() - - if(can_link) - add_library(std::filesystem INTERFACE IMPORTED) - set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17) - set(_found TRUE) - - if(CXX_FILESYSTEM_NO_LINK_NEEDED) - # Nothing to add... - elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED) - set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lstdc++fs) - elseif(CXX_FILESYSTEM_CPPFS_NEEDED) - set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lc++fs) - endif() - endif() -endif() - -cmake_pop_check_state() - -set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE) - -if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND) - message(FATAL_ERROR "Cannot run simple program using std::filesystem") -endif() diff --git a/dll/advapi32.cpp b/dll/advapi32.cpp index b35db8a..b2b559b 100644 --- a/dll/advapi32.cpp +++ b/dll/advapi32.cpp @@ -106,7 +106,7 @@ void *resolveByName(const char *name) { } // namespace -wibo::ModuleStub lib_advapi32 = { +extern const wibo::ModuleStub lib_advapi32 = { (const char *[]){ "advapi32", nullptr, diff --git a/dll/bcrypt.cpp b/dll/bcrypt.cpp index a743f76..da6d28c 100644 --- a/dll/bcrypt.cpp +++ b/dll/bcrypt.cpp @@ -74,7 +74,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::ModuleStub lib_bcrypt = { +extern const wibo::ModuleStub lib_bcrypt = { (const char *[]){ "bcrypt", nullptr, diff --git a/dll/crt.cpp b/dll/crt.cpp index c49eae7..f713677 100644 --- a/dll/crt.cpp +++ b/dll/crt.cpp @@ -463,7 +463,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::ModuleStub lib_crt = { +extern const wibo::ModuleStub lib_crt = { (const char *[]){ "api-ms-win-crt-heap-l1-1-0", "api-ms-win-crt-locale-l1-1-0", diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index 114bfbe..14dc483 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -9,8 +9,8 @@ #include "kernel32/interlockedapi.h" #include "kernel32/ioapiset.h" #include "kernel32/libloaderapi.h" -#include "kernel32/namedpipeapi.h" #include "kernel32/memoryapi.h" +#include "kernel32/namedpipeapi.h" #include "kernel32/processenv.h" #include "kernel32/processthreadsapi.h" #include "kernel32/profileapi.h" @@ -602,7 +602,7 @@ void *resolveByName(const char *name) { } // namespace -wibo::ModuleStub lib_kernel32 = { +extern const wibo::ModuleStub lib_kernel32 = { (const char *[]){ "kernel32", nullptr, diff --git a/dll/kernel32/fibersapi.cpp b/dll/kernel32/fibersapi.cpp index c763d09..019bb77 100644 --- a/dll/kernel32/fibersapi.cpp +++ b/dll/kernel32/fibersapi.cpp @@ -34,7 +34,7 @@ DWORD WIN_FUNC FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback) { BOOL WIN_FUNC FlsFree(DWORD dwFlsIndex) { HOST_CONTEXT_GUARD(); DEBUG_LOG("FlsFree(%u)\n", dwFlsIndex); - if (dwFlsIndex >= 0 && dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) { + if (dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) { g_flsValuesUsed[dwFlsIndex] = false; return TRUE; } else { @@ -47,7 +47,7 @@ PVOID WIN_FUNC FlsGetValue(DWORD dwFlsIndex) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("FlsGetValue(%u)\n", dwFlsIndex); PVOID result = nullptr; - if (dwFlsIndex >= 0 && dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) { + if (dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) { result = g_flsValues[dwFlsIndex]; // See https://learn.microsoft.com/en-us/windows/win32/api/fibersapi/nf-fibersapi-flsgetvalue wibo::lastError = ERROR_SUCCESS; @@ -61,7 +61,7 @@ PVOID WIN_FUNC FlsGetValue(DWORD dwFlsIndex) { BOOL WIN_FUNC FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("FlsSetValue(%u, %p)\n", dwFlsIndex, lpFlsData); - if (dwFlsIndex >= 0 && dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) { + if (dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) { g_flsValues[dwFlsIndex] = lpFlsData; return TRUE; } else { diff --git a/dll/kernel32/fileapi.cpp b/dll/kernel32/fileapi.cpp index 92ec82f..9c23ac9 100644 --- a/dll/kernel32/fileapi.cpp +++ b/dll/kernel32/fileapi.cpp @@ -717,11 +717,11 @@ BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr return FALSE; } - std::optional offset; + std::optional offset; bool updateFilePointer = true; if (lpOverlapped != nullptr) { - offset = static_cast((static_cast(lpOverlapped->Offset)) | - (static_cast(lpOverlapped->OffsetHigh) << 32)); + offset = static_cast((static_cast(lpOverlapped->Offset)) | + (static_cast(lpOverlapped->OffsetHigh) << 32)); lpOverlapped->Internal = STATUS_PENDING; lpOverlapped->InternalHigh = 0; updateFilePointer = !file->overlapped; @@ -736,9 +736,8 @@ BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr } return TRUE; } - auto asyncFile = file.clone(); - if (async_io::queueWrite(std::move(asyncFile), lpOverlapped, lpBuffer, nNumberOfBytesToWrite, offset, - file->isPipe)) { + if (wibo::asyncIO().queueWrite(file.clone(), lpOverlapped, lpBuffer, nNumberOfBytesToWrite, offset, + file->isPipe)) { if (lpNumberOfBytesWritten) { *lpNumberOfBytesWritten = 0; } @@ -814,11 +813,11 @@ BOOL WIN_FUNC ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead *lpNumberOfBytesRead = 0; } - std::optional offset; + std::optional offset; bool updateFilePointer = true; if (lpOverlapped != nullptr) { - offset = static_cast((static_cast(lpOverlapped->Offset)) | - (static_cast(lpOverlapped->OffsetHigh) << 32)); + offset = static_cast((static_cast(lpOverlapped->Offset)) | + (static_cast(lpOverlapped->OffsetHigh) << 32)); lpOverlapped->Internal = STATUS_PENDING; lpOverlapped->InternalHigh = 0; updateFilePointer = !file->overlapped; @@ -833,7 +832,8 @@ BOOL WIN_FUNC ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead } return TRUE; } - if (async_io::queueRead(file.clone(), lpOverlapped, lpBuffer, nNumberOfBytesToRead, offset, file->isPipe)) { + if (wibo::asyncIO().queueRead(file.clone(), lpOverlapped, lpBuffer, nNumberOfBytesToRead, offset, + file->isPipe)) { if (lpNumberOfBytesRead) { *lpNumberOfBytesRead = 0; } @@ -1193,14 +1193,14 @@ DWORD WIN_FUNC SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistan } // TODO access check std::lock_guard lk(file->m); - off64_t position = 0; - off64_t offset = static_cast(lDistanceToMove); + off_t position = 0; + off_t offset = static_cast(lDistanceToMove); if (dwMoveMethod == FILE_BEGIN) { position = offset; } else if (dwMoveMethod == FILE_CURRENT) { position = file->filePos + offset; } else if (dwMoveMethod == FILE_END) { - position = lseek64(file->fd, offset, SEEK_END); + position = lseek(file->fd, offset, SEEK_END); } if (position < 0) { if (errno == EINVAL) { @@ -1232,14 +1232,14 @@ BOOL WIN_FUNC SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLA } // TODO access check std::lock_guard lk(file->m); - off64_t position = 0; - off64_t offset = static_cast(liDistanceToMove); + off_t position = 0; + off_t offset = static_cast(liDistanceToMove); if (dwMoveMethod == FILE_BEGIN) { position = offset; } else if (dwMoveMethod == FILE_CURRENT) { position = file->filePos + offset; } else if (dwMoveMethod == FILE_END) { - position = lseek64(file->fd, offset, SEEK_END); + position = lseek(file->fd, offset, SEEK_END); } if (position < 0) { if (errno == EINVAL) { @@ -1279,7 +1279,7 @@ BOOL WIN_FUNC SetEndOfFile(HANDLE hFile) { setLastErrorFromErrno(); return FALSE; } - if (ftruncate64(file->fd, file->filePos) != 0) { + if (ftruncate(file->fd, file->filePos) != 0) { setLastErrorFromErrno(); return FALSE; } @@ -1338,7 +1338,7 @@ DWORD WIN_FUNC GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) { DEBUG_LOG("-> INVALID_FILE_SIZE (ERROR_INVALID_HANDLE)\n"); return INVALID_FILE_SIZE; } - const auto size = lseek64(file->fd, 0, SEEK_END); + const auto size = lseek(file->fd, 0, SEEK_END); if (size < 0) { if (lpFileSizeHigh) { *lpFileSizeHigh = 0; @@ -1480,8 +1480,8 @@ BOOL WIN_FUNC GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMAT return FALSE; } // TODO access check - struct stat64 st{}; - if (fstat64(file->fd, &st) != 0) { + struct stat st{}; + if (fstat(file->fd, &st) != 0) { setLastErrorFromErrno(); return FALSE; } diff --git a/dll/kernel32/interlockedapi.cpp b/dll/kernel32/interlockedapi.cpp index 9e06ded..ea3b70f 100644 --- a/dll/kernel32/interlockedapi.cpp +++ b/dll/kernel32/interlockedapi.cpp @@ -3,6 +3,7 @@ #include "common.h" #include "context.h" +#include #include namespace kernel32 { @@ -10,32 +11,33 @@ namespace kernel32 { LONG WIN_FUNC InterlockedIncrement(LONG volatile *Addend) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("InterlockedIncrement(%p)\n", Addend); - return ++(*Addend); + std::atomic_ref a(*const_cast(Addend)); + return a.fetch_add(1, std::memory_order_seq_cst) + 1; } LONG WIN_FUNC InterlockedDecrement(LONG volatile *Addend) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("InterlockedDecrement(%p)\n", Addend); - return --(*Addend); + std::atomic_ref a(*const_cast(Addend)); + return a.fetch_sub(1, std::memory_order_seq_cst) - 1; } LONG WIN_FUNC InterlockedExchange(LONG volatile *Target, LONG Value) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("InterlockedExchange(%p, %ld)\n", Target, static_cast(Value)); - LONG initial = *Target; - *Target = Value; - return initial; + std::atomic_ref a(*const_cast(Target)); + return a.exchange(Value, std::memory_order_seq_cst); } LONG WIN_FUNC InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("InterlockedCompareExchange(%p, %ld, %ld)\n", Destination, static_cast(Exchange), static_cast(Comperand)); - LONG original = *Destination; - if (original == Comperand) { - *Destination = Exchange; - } - return original; + + std::atomic_ref a(*const_cast(Destination)); + LONG expected = Comperand; + a.compare_exchange_strong(expected, Exchange, std::memory_order_seq_cst); + return expected; } void WIN_FUNC InitializeSListHead(PSLIST_HEADER ListHead) { diff --git a/dll/kernel32/internal.h b/dll/kernel32/internal.h index 919ba39..79b2330 100644 --- a/dll/kernel32/internal.h +++ b/dll/kernel32/internal.h @@ -26,14 +26,14 @@ struct FsObject : ObjectBase { struct FileObject final : FsObject { static constexpr ObjectType kType = ObjectType::File; - off64_t filePos = 0; + off_t filePos = 0; bool overlapped = false; bool appendOnly = false; bool isPipe = false; explicit FileObject(int fd) : FsObject(kType, fd) { if (fd >= 0) { - off64_t pos = lseek64(fd, 0, SEEK_CUR); + off_t pos = lseek(fd, 0, SEEK_CUR); if (pos == -1 && errno == ESPIPE) { isPipe = true; } else if (pos >= 0) { diff --git a/dll/kernel32/libloaderapi.cpp b/dll/kernel32/libloaderapi.cpp index 807a833..f5fe941 100644 --- a/dll/kernel32/libloaderapi.cpp +++ b/dll/kernel32/libloaderapi.cpp @@ -250,7 +250,8 @@ HMODULE WIN_FUNC LoadLibraryW(LPCWSTR lpLibFileName) { HMODULE WIN_FUNC LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) { HOST_CONTEXT_GUARD(); - assert(!hFile); + (void)hFile; + // TOOD: handle dwFlags properly DEBUG_LOG("LoadLibraryExW(%x) -> ", dwFlags); auto filename = wideStringToString(lpLibFileName); return LoadLibraryA(filename.c_str()); diff --git a/dll/kernel32/memoryapi.cpp b/dll/kernel32/memoryapi.cpp index 7f97182..b51358a 100644 --- a/dll/kernel32/memoryapi.cpp +++ b/dll/kernel32/memoryapi.cpp @@ -502,7 +502,7 @@ HANDLE WIN_FUNC CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMap } mapping->fd = dupFd; if (size == 0) { - off64_t fileSize = lseek64(dupFd, 0, SEEK_END); + off_t fileSize = lseek(dupFd, 0, SEEK_END); if (fileSize < 0) { return nullptr; } diff --git a/dll/kernel32/synchapi.cpp b/dll/kernel32/synchapi.cpp index 9dd0bd4..2214410 100644 --- a/dll/kernel32/synchapi.cpp +++ b/dll/kernel32/synchapi.cpp @@ -635,26 +635,31 @@ BOOL WIN_FUNC InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpC void WIN_FUNC AcquireSRWLockShared(PSRWLOCK SRWLock) { HOST_CONTEXT_GUARD(); + (void)SRWLock; VERBOSE_LOG("STUB: AcquireSRWLockShared(%p)\n", SRWLock); } void WIN_FUNC ReleaseSRWLockShared(PSRWLOCK SRWLock) { HOST_CONTEXT_GUARD(); + (void)SRWLock; VERBOSE_LOG("STUB: ReleaseSRWLockShared(%p)\n", SRWLock); } void WIN_FUNC AcquireSRWLockExclusive(PSRWLOCK SRWLock) { HOST_CONTEXT_GUARD(); + (void)SRWLock; VERBOSE_LOG("STUB: AcquireSRWLockExclusive(%p)\n", SRWLock); } void WIN_FUNC ReleaseSRWLockExclusive(PSRWLOCK SRWLock) { HOST_CONTEXT_GUARD(); + (void)SRWLock; VERBOSE_LOG("STUB: ReleaseSRWLockExclusive(%p)\n", SRWLock); } BOOLEAN WIN_FUNC TryAcquireSRWLockExclusive(PSRWLOCK SRWLock) { HOST_CONTEXT_GUARD(); + (void)SRWLock; VERBOSE_LOG("STUB: TryAcquireSRWLockExclusive(%p)\n", SRWLock); return TRUE; } diff --git a/dll/kernel32/timeutil.h b/dll/kernel32/timeutil.h index 3492c3b..b30af51 100644 --- a/dll/kernel32/timeutil.h +++ b/dll/kernel32/timeutil.h @@ -72,16 +72,16 @@ inline bool validateSystemTime(const SYSTEMTIME &st) { if (st.wDay < 1 || st.wDay > static_cast(daysInMonth(st.wYear, static_cast(st.wMonth)))) { return false; } - if (st.wHour < 0 || st.wHour > 23) { + if (st.wHour > 23) { return false; } - if (st.wMinute < 0 || st.wMinute > 59) { + if (st.wMinute > 59) { return false; } - if (st.wSecond < 0 || st.wSecond > 59) { + if (st.wSecond > 59) { return false; } - if (st.wMilliseconds < 0 || st.wMilliseconds > 999) { + if (st.wMilliseconds > 999) { return false; } return true; diff --git a/dll/lmgr.cpp b/dll/lmgr.cpp index 9842a7a..4ab6c62 100644 --- a/dll/lmgr.cpp +++ b/dll/lmgr.cpp @@ -27,7 +27,7 @@ static void *resolveByOrdinal(uint16_t ordinal) { return 0; } -wibo::ModuleStub lib_lmgr = { +extern const wibo::ModuleStub lib_lmgr = { (const char *[]){ "lmgr11", "lmgr326b", diff --git a/dll/mscoree.cpp b/dll/mscoree.cpp index 46016f6..bd270a4 100644 --- a/dll/mscoree.cpp +++ b/dll/mscoree.cpp @@ -18,7 +18,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::ModuleStub lib_mscoree = { +extern const wibo::ModuleStub lib_mscoree = { (const char *[]){ "mscoree", nullptr, diff --git a/dll/msvcrt.cpp b/dll/msvcrt.cpp index 0080676..c324bb6 100644 --- a/dll/msvcrt.cpp +++ b/dll/msvcrt.cpp @@ -2600,6 +2600,7 @@ namespace msvcrt { HOST_CONTEXT_GUARD(); VERBOSE_LOG("_itow_s(%d, %p, %zu, %d)\n", value, buffer, size, radix); if (!buffer || size == 0) return 22; + (void)radix; assert(radix == 10); // only base 10 supported for now std::string str = std::to_string(value); @@ -3222,7 +3223,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::ModuleStub lib_msvcrt = { +extern const wibo::ModuleStub lib_msvcrt = { (const char *[]){ "msvcrt", "msvcrt40", diff --git a/dll/ntdll.cpp b/dll/ntdll.cpp index a0b6447..a485ad1 100644 --- a/dll/ntdll.cpp +++ b/dll/ntdll.cpp @@ -152,9 +152,9 @@ NTSTATUS WIN_FUNC NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE Ap useCurrentFilePosition = true; } - std::optional offset; + std::optional offset; if (!useCurrentFilePosition) { - offset = static_cast(*ByteOffset); + offset = static_cast(*ByteOffset); } if (useOverlapped && useCurrentFilePosition) { @@ -423,7 +423,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::ModuleStub lib_ntdll = { +extern const wibo::ModuleStub lib_ntdll = { (const char *[]){ "ntdll", nullptr, diff --git a/dll/ole32.cpp b/dll/ole32.cpp index 7866618..43c72b2 100644 --- a/dll/ole32.cpp +++ b/dll/ole32.cpp @@ -39,7 +39,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::ModuleStub lib_ole32 = { +extern const wibo::ModuleStub lib_ole32 = { (const char *[]){ "ole32", nullptr, diff --git a/dll/rpcrt4.cpp b/dll/rpcrt4.cpp index beb20e1..c6d13d7 100644 --- a/dll/rpcrt4.cpp +++ b/dll/rpcrt4.cpp @@ -285,7 +285,7 @@ void *resolveByName(const char *name) { } // namespace -wibo::ModuleStub lib_rpcrt4 = { +extern const wibo::ModuleStub lib_rpcrt4 = { (const char *[]){"rpcrt4", nullptr}, resolveByName, nullptr, diff --git a/dll/user32.cpp b/dll/user32.cpp index 7e5db14..9abe99e 100644 --- a/dll/user32.cpp +++ b/dll/user32.cpp @@ -120,6 +120,8 @@ namespace user32 { int WIN_FUNC MessageBoxA(void *hwnd, const char *lpText, const char *lpCaption, unsigned int uType) { HOST_CONTEXT_GUARD(); + (void)hwnd; + (void)uType; printf("MESSAGE BOX: [%s] %s\n", lpCaption, lpText); fflush(stdout); return 1; @@ -183,7 +185,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::ModuleStub lib_user32 = { +extern const wibo::ModuleStub lib_user32 = { (const char *[]){ "user32", nullptr, diff --git a/dll/vcruntime.cpp b/dll/vcruntime.cpp index 9e45c0a..2e93c83 100644 --- a/dll/vcruntime.cpp +++ b/dll/vcruntime.cpp @@ -38,7 +38,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::ModuleStub lib_vcruntime = { +extern const wibo::ModuleStub lib_vcruntime = { (const char *[]){ "vcruntime140", nullptr, diff --git a/dll/version.cpp b/dll/version.cpp index c95107f..d90c78d 100644 --- a/dll/version.cpp +++ b/dll/version.cpp @@ -327,7 +327,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::ModuleStub lib_version = { +extern const wibo::ModuleStub lib_version = { (const char *[]){ "version", nullptr, diff --git a/src/async_io.cpp b/src/async_io.cpp index bad2a6c..aa9b105 100644 --- a/src/async_io.cpp +++ b/src/async_io.cpp @@ -1,277 +1,56 @@ #include "async_io.h" -#include "common.h" -#include "errors.h" -#include "kernel32/overlapped_util.h" +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace async_io { namespace { -constexpr unsigned kQueueDepth = 64; +std::unique_ptr g_backend; -struct AsyncRequest { - enum class Kind { Read, Write, Shutdown }; - - Kind kind; - Pin file; - OVERLAPPED *overlapped = nullptr; - bool isPipe = false; - struct iovec vec{}; -}; - -class IoUringBackend { +class DummyBackend : public wibo::AsyncIOBackend { public: - ~IoUringBackend() { shutdown(); } - bool init(); - void shutdown(); - [[nodiscard]] bool running() const noexcept { return mRunning.load(std::memory_order_acquire); } + bool init() override { return true; } + void shutdown() override {} + [[nodiscard]] bool running() const noexcept override { return true; } bool queueRead(Pin file, OVERLAPPED *ov, void *buffer, DWORD length, - const std::optional &offset, bool isPipe); + const std::optional &offset, bool isPipe) override { + (void)file; + (void)ov; + (void)buffer; + (void)length; + (void)offset; + (void)isPipe; + return false; + } bool queueWrite(Pin file, OVERLAPPED *ov, const void *buffer, DWORD length, - const std::optional &offset, bool isPipe); - - private: - bool enqueueRequest(AsyncRequest *req, void *buffer, DWORD length, const std::optional &offset, - bool isWrite); - void requestStop(); - void workerLoop(); - void handleCompletion(struct io_uring_cqe *cqe); - void notifySpace(); - - struct io_uring mRing{}; - std::mutex mSubmitMutex; - std::condition_variable mQueueCv; - std::atomic mRunning{false}; - std::atomic mPending{0}; - std::thread mThread; + const std::optional &offset, bool isPipe) override { + (void)file; + (void)ov; + (void)buffer; + (void)length; + (void)offset; + (void)isPipe; + return false; + } }; -IoUringBackend gBackend; - } // namespace -bool initialize() { - if (gBackend.running()) { - return true; +namespace wibo { + +AsyncIOBackend &asyncIO() { + if (!g_backend) { +#if WIBO_ENABLE_LIBURING + g_backend = detail::createIoUringBackend(); +#else + g_backend = std::make_unique(); +#endif } - return gBackend.init(); + if (!g_backend->init()) { + fprintf(stderr, "asyncIO: failed to initialize backend\n"); + abort(); + } + return *g_backend; } -void shutdown() { gBackend.shutdown(); } - -bool running() { return gBackend.running(); } - -bool queueRead(Pin file, OVERLAPPED *ov, void *buffer, DWORD length, - const std::optional &offset, bool isPipe) { - if (!gBackend.running()) { - return false; - } - return gBackend.queueRead(std::move(file), ov, buffer, length, offset, isPipe); -} - -bool queueWrite(Pin file, OVERLAPPED *ov, const void *buffer, DWORD length, - const std::optional &offset, bool isPipe) { - if (!gBackend.running()) { - return false; - } - return gBackend.queueWrite(std::move(file), ov, buffer, length, offset, isPipe); -} - -bool IoUringBackend::init() { - if (mRunning.load(std::memory_order_acquire)) { - return true; - } - int rc = io_uring_queue_init(kQueueDepth, &mRing, 0); - if (rc < 0) { - DEBUG_LOG("io_uring_queue_init failed: %d\n", rc); - return false; - } - mRunning.store(true, std::memory_order_release); - mThread = std::thread(&IoUringBackend::workerLoop, this); - DEBUG_LOG("io_uring backend initialized (depth=%u)\n", kQueueDepth); - return true; -} - -void IoUringBackend::shutdown() { - if (!mRunning.exchange(false, std::memory_order_acq_rel)) { - return; - } - requestStop(); - if (mThread.joinable()) { - mThread.join(); - } - io_uring_queue_exit(&mRing); -} - -bool IoUringBackend::queueRead(Pin file, OVERLAPPED *ov, void *buffer, DWORD length, - const std::optional &offset, bool isPipe) { - auto *req = new AsyncRequest{AsyncRequest::Kind::Read, std::move(file), ov, isPipe}; - if (!enqueueRequest(req, buffer, length, offset, false)) { - delete req; - return false; - } - return true; -} - -bool IoUringBackend::queueWrite(Pin file, OVERLAPPED *ov, const void *buffer, DWORD length, - const std::optional &offset, bool isPipe) { - auto *req = new AsyncRequest{AsyncRequest::Kind::Write, std::move(file), ov, isPipe}; - if (!enqueueRequest(req, const_cast(buffer), length, offset, true)) { - delete req; - return false; - } - return true; -} - -bool IoUringBackend::enqueueRequest(AsyncRequest *req, void *buffer, DWORD length, const std::optional &offset, - bool isWrite) { - std::unique_lock lock(mSubmitMutex); - if (!mRunning.load(std::memory_order_acquire) && req->kind != AsyncRequest::Kind::Shutdown) { - return false; - } - - struct io_uring_sqe *sqe; - while (true) { - sqe = io_uring_get_sqe(&mRing); - if (!sqe) { - mQueueCv.wait(lock); - if (!mRunning.load(std::memory_order_acquire) && req->kind != AsyncRequest::Kind::Shutdown) { - return false; - } - continue; - } - io_uring_sqe_set_data(sqe, req); - if (req->kind == AsyncRequest::Kind::Shutdown) { - io_uring_prep_nop(sqe); - } else { - req->vec.iov_base = buffer; - req->vec.iov_len = length; - off64_t fileOffset = -1; - if (!req->isPipe && offset.has_value()) { - fileOffset = *offset; - } - int fd = req->file ? req->file->fd : -1; - if (isWrite) { - io_uring_prep_writev(sqe, fd, &req->vec, 1, fileOffset); - } else { - io_uring_prep_readv(sqe, fd, &req->vec, 1, fileOffset); - } - } - mPending.fetch_add(1, std::memory_order_relaxed); - break; - } - - while (true) { - int res = io_uring_submit(&mRing); - if (res >= 0) { - break; - } else if (res == -EINTR) { - continue; - } else if (res == -EBUSY || res == -EAGAIN) { - lock.unlock(); - std::this_thread::yield(); - lock.lock(); - continue; - } - DEBUG_LOG("io_uring_submit failed (will retry): %d\n", res); - } - - lock.unlock(); - mQueueCv.notify_one(); - return true; -} - -void IoUringBackend::requestStop() { - mRunning.store(false, std::memory_order_release); - auto *req = new AsyncRequest{AsyncRequest::Kind::Shutdown, Pin{}, nullptr, false}; - if (!enqueueRequest(req, nullptr, 0, std::nullopt, false)) { - delete req; - } -} - -void IoUringBackend::workerLoop() { - while (mRunning.load(std::memory_order_acquire) || mPending.load(std::memory_order_acquire) > 0) { - struct io_uring_cqe *cqe = nullptr; - int ret = io_uring_wait_cqe(&mRing, &cqe); - if (ret == -EINTR) { - continue; - } - if (ret < 0) { - DEBUG_LOG("io_uring_wait_cqe failed: %d\n", ret); - continue; - } - handleCompletion(cqe); - io_uring_cqe_seen(&mRing, cqe); - notifySpace(); - } - - while (mPending.load(std::memory_order_acquire) > 0) { - struct io_uring_cqe *cqe = nullptr; - int ret = io_uring_peek_cqe(&mRing, &cqe); - if (ret != 0 || !cqe) { - break; - } - handleCompletion(cqe); - io_uring_cqe_seen(&mRing, cqe); - notifySpace(); - } -} - -void IoUringBackend::handleCompletion(struct io_uring_cqe *cqe) { - auto *req = static_cast(io_uring_cqe_get_data(cqe)); - if (!req) { - return; - } - - if (req->kind == AsyncRequest::Kind::Shutdown) { - delete req; - mPending.fetch_sub(1, std::memory_order_acq_rel); - return; - } - - OVERLAPPED *ov = req->overlapped; - if (ov) { - if (cqe->res >= 0) { - ov->InternalHigh = static_cast(cqe->res); - if (req->kind == AsyncRequest::Kind::Read && cqe->res == 0) { - ov->Internal = req->isPipe ? STATUS_PIPE_BROKEN : STATUS_END_OF_FILE; - } else { - ov->Internal = STATUS_SUCCESS; - } - } else { - int err = -cqe->res; - ov->InternalHigh = 0; - if (err == EPIPE) { - ov->Internal = STATUS_PIPE_BROKEN; - } else { - NTSTATUS status = wibo::statusFromErrno(err); - if (status == STATUS_SUCCESS) { - status = STATUS_UNEXPECTED_IO_ERROR; - } - ov->Internal = status; - } - } - kernel32::detail::signalOverlappedEvent(ov); - } - - delete req; - mPending.fetch_sub(1, std::memory_order_acq_rel); -} - -void IoUringBackend::notifySpace() { - std::lock_guard lk(mSubmitMutex); - mQueueCv.notify_all(); -} - -} // namespace async_io +} // namespace wibo diff --git a/src/async_io.h b/src/async_io.h index c922ec8..4674b37 100644 --- a/src/async_io.h +++ b/src/async_io.h @@ -5,15 +5,28 @@ #include -namespace async_io { +namespace wibo { -bool initialize(); -void shutdown(); -bool running(); +class AsyncIOBackend { + public: + virtual ~AsyncIOBackend() = default; + virtual bool init() = 0; + virtual void shutdown() = 0; + [[nodiscard]] virtual bool running() const noexcept = 0; + virtual bool queueRead(Pin file, OVERLAPPED *ov, void *buffer, DWORD length, + const std::optional &offset, bool isPipe) = 0; + virtual bool queueWrite(Pin file, OVERLAPPED *ov, const void *buffer, DWORD length, + const std::optional &offset, bool isPipe) = 0; +}; -bool queueRead(Pin file, OVERLAPPED *ov, void *buffer, DWORD length, - const std::optional &offset, bool isPipe); -bool queueWrite(Pin file, OVERLAPPED *ov, const void *buffer, DWORD length, - const std::optional &offset, bool isPipe); +namespace detail { -} // namespace async_io +#if WIBO_ENABLE_LIBURING +std::unique_ptr createIoUringBackend(); +#endif + +} // namespace detail + +AsyncIOBackend &asyncIO(); + +} // namespace wibo diff --git a/src/async_io_uring.cpp b/src/async_io_uring.cpp new file mode 100644 index 0000000..b319e7d --- /dev/null +++ b/src/async_io_uring.cpp @@ -0,0 +1,244 @@ +#include "async_io.h" + +#include "errors.h" +#include "kernel32/internal.h" +#include "kernel32/overlapped_util.h" + +#include +#include + +namespace { + +constexpr unsigned kQueueDepth = 64; + +struct AsyncRequest { + enum class Kind { Read, Write, Shutdown }; + + Kind kind; + Pin file; + OVERLAPPED *overlapped = nullptr; + bool isPipe = false; + struct iovec vec{}; +}; + +class IoUringBackend : public wibo::AsyncIOBackend { + public: + ~IoUringBackend() override { shutdown(); } + bool init() override; + void shutdown() override; + [[nodiscard]] bool running() const noexcept override { return mRunning.load(std::memory_order_acquire); } + + bool queueRead(Pin file, OVERLAPPED *ov, void *buffer, DWORD length, + const std::optional &offset, bool isPipe) override; + bool queueWrite(Pin file, OVERLAPPED *ov, const void *buffer, DWORD length, + const std::optional &offset, bool isPipe) override; + + private: + bool enqueueRequest(AsyncRequest *req, void *buffer, DWORD length, const std::optional &offset, + bool isWrite); + void requestStop(); + void workerLoop(); + void handleCompletion(struct io_uring_cqe *cqe); + void notifySpace(); + + struct io_uring mRing{}; + std::mutex mSubmitMutex; + std::condition_variable mQueueCv; + std::atomic mRunning{false}; + std::atomic mPending{0}; + std::thread mThread; +}; + +bool IoUringBackend::init() { + if (mRunning.load(std::memory_order_acquire)) { + return true; + } + int rc = io_uring_queue_init(kQueueDepth, &mRing, 0); + if (rc < 0) { + DEBUG_LOG("io_uring_queue_init failed: %d\n", rc); + return false; + } + mRunning.store(true, std::memory_order_release); + mThread = std::thread(&IoUringBackend::workerLoop, this); + DEBUG_LOG("io_uring backend initialized (depth=%u)\n", kQueueDepth); + return true; +} + +void IoUringBackend::shutdown() { + if (!mRunning.exchange(false, std::memory_order_acq_rel)) { + return; + } + requestStop(); + if (mThread.joinable()) { + mThread.join(); + } + io_uring_queue_exit(&mRing); +} + +bool IoUringBackend::queueRead(Pin file, OVERLAPPED *ov, void *buffer, DWORD length, + const std::optional &offset, bool isPipe) { + auto *req = new AsyncRequest{AsyncRequest::Kind::Read, std::move(file), ov, isPipe}; + if (!enqueueRequest(req, buffer, length, offset, false)) { + delete req; + return false; + } + return true; +} + +bool IoUringBackend::queueWrite(Pin file, OVERLAPPED *ov, const void *buffer, DWORD length, + const std::optional &offset, bool isPipe) { + auto *req = new AsyncRequest{AsyncRequest::Kind::Write, std::move(file), ov, isPipe}; + if (!enqueueRequest(req, const_cast(buffer), length, offset, true)) { + delete req; + return false; + } + return true; +} + +bool IoUringBackend::enqueueRequest(AsyncRequest *req, void *buffer, DWORD length, const std::optional &offset, + bool isWrite) { + std::unique_lock lock(mSubmitMutex); + if (!mRunning.load(std::memory_order_acquire) && req->kind != AsyncRequest::Kind::Shutdown) { + return false; + } + + struct io_uring_sqe *sqe; + while (true) { + sqe = io_uring_get_sqe(&mRing); + if (!sqe) { + mQueueCv.wait(lock); + if (!mRunning.load(std::memory_order_acquire) && req->kind != AsyncRequest::Kind::Shutdown) { + return false; + } + continue; + } + io_uring_sqe_set_data(sqe, req); + if (req->kind == AsyncRequest::Kind::Shutdown) { + io_uring_prep_nop(sqe); + } else { + req->vec.iov_base = buffer; + req->vec.iov_len = length; + off_t fileOffset = -1; + if (!req->isPipe && offset.has_value()) { + fileOffset = *offset; + } + int fd = req->file ? req->file->fd : -1; + if (isWrite) { + io_uring_prep_writev(sqe, fd, &req->vec, 1, fileOffset); + } else { + io_uring_prep_readv(sqe, fd, &req->vec, 1, fileOffset); + } + } + mPending.fetch_add(1, std::memory_order_relaxed); + break; + } + + while (true) { + int res = io_uring_submit(&mRing); + if (res >= 0) { + break; + } else if (res == -EINTR) { + continue; + } else if (res == -EBUSY || res == -EAGAIN) { + lock.unlock(); + std::this_thread::yield(); + lock.lock(); + continue; + } + DEBUG_LOG("io_uring_submit failed (will retry): %d\n", res); + } + + lock.unlock(); + mQueueCv.notify_one(); + return true; +} + +void IoUringBackend::requestStop() { + mRunning.store(false, std::memory_order_release); + auto *req = new AsyncRequest{AsyncRequest::Kind::Shutdown, Pin{}, nullptr, false}; + if (!enqueueRequest(req, nullptr, 0, std::nullopt, false)) { + delete req; + } +} + +void IoUringBackend::workerLoop() { + while (mRunning.load(std::memory_order_acquire) || mPending.load(std::memory_order_acquire) > 0) { + struct io_uring_cqe *cqe = nullptr; + int ret = io_uring_wait_cqe(&mRing, &cqe); + if (ret == -EINTR) { + continue; + } + if (ret < 0) { + DEBUG_LOG("io_uring_wait_cqe failed: %d\n", ret); + continue; + } + handleCompletion(cqe); + io_uring_cqe_seen(&mRing, cqe); + notifySpace(); + } + + while (mPending.load(std::memory_order_acquire) > 0) { + struct io_uring_cqe *cqe = nullptr; + int ret = io_uring_peek_cqe(&mRing, &cqe); + if (ret != 0 || !cqe) { + break; + } + handleCompletion(cqe); + io_uring_cqe_seen(&mRing, cqe); + notifySpace(); + } +} + +void IoUringBackend::handleCompletion(struct io_uring_cqe *cqe) { + auto *req = static_cast(io_uring_cqe_get_data(cqe)); + if (!req) { + return; + } + + if (req->kind == AsyncRequest::Kind::Shutdown) { + delete req; + mPending.fetch_sub(1, std::memory_order_acq_rel); + return; + } + + OVERLAPPED *ov = req->overlapped; + if (ov) { + if (cqe->res >= 0) { + ov->InternalHigh = static_cast(cqe->res); + if (req->kind == AsyncRequest::Kind::Read && cqe->res == 0) { + ov->Internal = req->isPipe ? STATUS_PIPE_BROKEN : STATUS_END_OF_FILE; + } else { + ov->Internal = STATUS_SUCCESS; + } + } else { + int err = -cqe->res; + ov->InternalHigh = 0; + if (err == EPIPE) { + ov->Internal = STATUS_PIPE_BROKEN; + } else { + NTSTATUS status = wibo::statusFromErrno(err); + if (status == STATUS_SUCCESS) { + status = STATUS_UNEXPECTED_IO_ERROR; + } + ov->Internal = status; + } + } + kernel32::detail::signalOverlappedEvent(ov); + } + + delete req; + mPending.fetch_sub(1, std::memory_order_acq_rel); +} + +void IoUringBackend::notifySpace() { + std::lock_guard lk(mSubmitMutex); + mQueueCv.notify_all(); +} + +} // namespace + +namespace wibo::detail { + +std::unique_ptr createIoUringBackend() { return std::make_unique(); } + +} // namespace wibo::detail diff --git a/src/common.h b/src/common.h index 9fab80f..744f8c1 100644 --- a/src/common.h +++ b/src/common.h @@ -13,11 +13,7 @@ // On Windows, the incoming stack is aligned to a 4 byte boundary. // force_align_arg_pointer will realign the stack to match GCC's 16 byte alignment. -#ifdef __clang__ -#define WIN_ENTRY __attribute__((force_align_arg_pointer)) -#else -#define WIN_ENTRY __attribute__((force_align_arg_pointer, callee_pop_aggregate_return(0))) -#endif +#define WIN_ENTRY __attribute__((ms_abi, force_align_arg_pointer)) #define WIN_FUNC WIN_ENTRY __attribute__((stdcall)) #define DEBUG_LOG(...) \ diff --git a/src/files.cpp b/src/files.cpp index 4bc575b..efdc0fd 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -142,7 +142,7 @@ std::string pathToWindows(const std::filesystem::path &path) { return str; } -IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::optional &offset, +IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::optional &offset, bool updateFilePointer) { IOResult result{}; if (!file || !file->valid()) { @@ -180,13 +180,13 @@ IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::opt return result; } - const auto doRead = [&](off64_t pos) { + const auto doRead = [&](off_t pos) { size_t total = 0; size_t remaining = bytesToRead; uint8_t *in = static_cast(buffer); while (remaining > 0) { size_t chunk = remaining > SSIZE_MAX ? SSIZE_MAX : remaining; - ssize_t rc = pread64(file->fd, in + total, chunk, pos); + ssize_t rc = pread(file->fd, in + total, chunk, pos); if (rc == -1) { if (errno == EINTR) { continue; @@ -207,10 +207,10 @@ IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::opt if (updateFilePointer || !offset.has_value()) { std::lock_guard lk(file->m); - const off64_t pos = offset.value_or(file->filePos); + const off_t pos = offset.value_or(file->filePos); doRead(pos); if (updateFilePointer) { - file->filePos = pos + static_cast(result.bytesTransferred); + file->filePos = pos + static_cast(result.bytesTransferred); } } else { doRead(*offset); @@ -219,7 +219,7 @@ IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::opt return result; } -IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const std::optional &offset, +IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const std::optional &offset, bool updateFilePointer) { IOResult result{}; if (!file || !file->valid()) { @@ -256,7 +256,7 @@ IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const } result.bytesTransferred = total; if (updateFilePointer) { - off64_t pos = file->isPipe ? 0 : lseek64(file->fd, 0, SEEK_CUR); + off_t pos = file->isPipe ? 0 : lseek(file->fd, 0, SEEK_CUR); if (pos >= 0) { file->filePos = pos; } else if (result.unixError == 0) { @@ -266,13 +266,13 @@ IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const return result; } - auto doWrite = [&](off64_t pos) { + auto doWrite = [&](off_t pos) { size_t total = 0; size_t remaining = bytesToWrite; const uint8_t *in = static_cast(buffer); while (remaining > 0) { size_t chunk = remaining > SSIZE_MAX ? SSIZE_MAX : remaining; - ssize_t rc = pwrite64(file->fd, in + total, chunk, pos); + ssize_t rc = pwrite(file->fd, in + total, chunk, pos); if (rc == -1) { if (errno == EINTR) { continue; @@ -292,10 +292,10 @@ IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const if (updateFilePointer || !offset.has_value()) { std::lock_guard lk(file->m); - const off64_t pos = offset.value_or(file->filePos); + const off_t pos = offset.value_or(file->filePos); doWrite(pos); if (updateFilePointer) { - file->filePos = pos + static_cast(result.bytesTransferred); + file->filePos = pos + static_cast(result.bytesTransferred); } } else { doWrite(*offset); diff --git a/src/files.h b/src/files.h index efe195b..df1c73d 100644 --- a/src/files.h +++ b/src/files.h @@ -21,9 +21,9 @@ struct IOResult { void init(); std::filesystem::path pathFromWindows(const char *inStr); std::string pathToWindows(const std::filesystem::path &path); -IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::optional &offset, +IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::optional &offset, bool updateFilePointer); -IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const std::optional &offset, +IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const std::optional &offset, bool updateFilePointer); HANDLE getStdHandle(DWORD nStdHandle); BOOL setStdHandle(DWORD nStdHandle, HANDLE hHandle); diff --git a/src/main.cpp b/src/main.cpp index 4099a3b..dc8a439 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ -#include "common.h" #include "async_io.h" +#include "common.h" #include "context.h" #include "files.h" #include "modules.h" @@ -408,14 +408,13 @@ int main(int argc, char **argv) { blockUpper2GB(); files::init(); - wibo::processes().init(); - async_io::initialize(); // Create TIB memset(&tib, 0, sizeof(tib)); tib.tib = &tib; - tib.peb = (PEB *)calloc(sizeof(PEB), 1); - tib.peb->ProcessParameters = (RTL_USER_PROCESS_PARAMETERS *)calloc(sizeof(RTL_USER_PROCESS_PARAMETERS), 1); + tib.peb = static_cast(calloc(1, sizeof(PEB))); + tib.peb->ProcessParameters = + static_cast(calloc(1, sizeof(RTL_USER_PROCESS_PARAMETERS))); wibo::processPeb = tib.peb; wibo::initializeTibStackInfo(&tib); if (!wibo::installTibForCurrentThread(&tib)) { diff --git a/src/processes.cpp b/src/processes.cpp index 14eaeb5..f636c4f 100644 --- a/src/processes.cpp +++ b/src/processes.cpp @@ -74,6 +74,7 @@ bool ProcessManager::init() { mRunning.store(true, std::memory_order_release); mThread = std::thread(&ProcessManager::runLoop, this); + DEBUG_LOG("ProcessManager initialized\n"); return true; } @@ -159,7 +160,7 @@ void ProcessManager::wake() const { return; } uint64_t n = 1; - write(mWakeFd, &n, sizeof(n)); + ssize_t r [[maybe_unused]] = write(mWakeFd, &n, sizeof(n)); } void ProcessManager::checkPidfd(int pidfd) { @@ -212,6 +213,10 @@ void ProcessManager::checkPidfd(int pidfd) { ProcessManager &processes() { static ProcessManager mgr; + if (!mgr.init()) { + fprintf(stderr, "Failed to initialize ProcessManager\n"); + abort(); + } return mgr; } diff --git a/src/resources.cpp b/src/resources.cpp index 3b8a35c..f7319ee 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -99,9 +99,8 @@ const wibo::ImageResourceDataEntry *entryAsData(const uint8_t *base, const Image uint16_t primaryLang(uint16_t lang) { return lang & 0x3FFu; } -const ImageResourceDirectoryEntry *selectLanguageEntry(const ImageResourceDirectory *dir, const uint8_t *base, - uint32_t rsrcSize, std::optional desired, - uint16_t &chosenLang) { +const ImageResourceDirectoryEntry *selectLanguageEntry(const ImageResourceDirectory *dir, + std::optional desired, uint16_t &chosenLang) { const auto *entries = resourceEntries(dir); uint16_t total = dir->numberOfNamedEntries + dir->numberOfIdEntries; const ImageResourceDirectoryEntry *primaryMatch = nullptr; @@ -172,7 +171,7 @@ bool Executable::findResource(const ResourceIdentifier &type, const ResourceIden return false; } uint16_t chosenLang = language.value_or(0); - const auto *langEntry = selectLanguageEntry(langDir, base, rsrcSize, language, chosenLang); + const auto *langEntry = selectLanguageEntry(langDir, language, chosenLang); if (!langEntry) { wibo::lastError = ERROR_RESOURCE_LANG_NOT_FOUND; return false;