Skip to content

Commit

Permalink
Support cross-compiling and MinGW
Browse files Browse the repository at this point in the history
  • Loading branch information
nthirtyone committed Feb 26, 2024
1 parent d64a0c9 commit 0daefae
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 70 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Expand Up @@ -33,6 +33,31 @@ jobs:
- name: Run Tests
run: ctest --test-dir infoware/build

mingw:
name: Linux MinGW (${{matrix.arch.pkg}})
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
arch:
- { pkg: i686, paths: i686 }
- { pkg: x86-64, paths: x86_64 }

steps:
- name: Checkout infoware
uses: actions/checkout@v2
with:
path: infoware

- name: Install apt packages
run: sudo apt update && sudo apt install -y cmake ninja-build g++-mingw-w64-${{matrix.arch.pkg}}

- name: Generate CMake
run: mkdir infoware/build && cd infoware/build && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../tools/${{matrix.arch.paths}}-w64-mingw32.cmake -G Ninja ..

- name: Build Project
run: cmake --build infoware/build

macos:
name: macOS ${{matrix.os}} ${{matrix.arch}}
runs-on: ${{matrix.os}}
Expand Down
102 changes: 58 additions & 44 deletions CMakeLists.txt
Expand Up @@ -84,54 +84,64 @@ if(NOT Git_FOUND) # Could be pre-injected
find_package(Git)
endif()

set(infoware_pci_ids_error "\
The pci.ids file, downloadable from https://github.com/pciutils/pciids or http://pci-ids.ucw.cz, is required for building infoware, \
and cloned automatically from that GitHub repository by default.\n\
To use a local copy, set INFOWARE_PCI_IDS_PATH to its location.")
if(INFOWARE_PCI_IDS_PATH)
if(NOT EXISTS "${INFOWARE_PCI_IDS_PATH}")
message(WARNING "The specified pci.ids file INFOWARE_PCI_IDS_PATH=${INFOWARE_PCI_IDS_PATH} doesn't seem to exist.")
endif()
set(infoware_pci_ids_file "${INFOWARE_PCI_IDS_PATH}")
elseif(NOT Git_FOUND)
message(SEND_ERROR "Couldn't find a usable git executable in the environment, and the CMake variable INFOWARE_PCI_IDS_PATH is empty.\n${infoware_pci_ids_error}")
else()
# Thanks, @griwes
set(infoware_pci_ids_file "${CMAKE_CURRENT_BINARY_DIR}/pciids/pci.ids")
if(EXISTS "${infoware_pci_ids_file}")
execute_process(COMMAND "${GIT_EXECUTABLE}" remote set-url origin "${INFOWARE_PCI_IDS_REPOSITORY}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pciids")
execute_process(COMMAND "${GIT_EXECUTABLE}" pull
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pciids"
RESULT_VARIABLE infoware_git_pciids_clone_err)
set(INFOWARE_PCI_DATA_DIR infoware_generated CACHE PATH "Output directory for the PCI ids generator")
set(INFOWARE_PCI_DATA_HPP pci_data.hpp)
set(INFOWARE_PCI_DATA_GEN "${INFOWARE_PCI_DATA_DIR}/${INFOWARE_PCI_DATA_HPP}")
if(NOT CMAKE_CROSSCOMPILING)
set(infoware_pci_ids_error "\
The pci.ids file, downloadable from https://github.com/pciutils/pciids or http://pci-ids.ucw.cz, is required for building infoware, \
and cloned automatically from that GitHub repository by default.\n\
To use a local copy, set INFOWARE_PCI_IDS_PATH to its location.")
if(INFOWARE_PCI_IDS_PATH)
if(NOT EXISTS "${INFOWARE_PCI_IDS_PATH}")
message(WARNING "The specified pci.ids file INFOWARE_PCI_IDS_PATH=${INFOWARE_PCI_IDS_PATH} doesn't seem to exist.")
endif()
set(infoware_pci_ids_file "${INFOWARE_PCI_IDS_PATH}")
elseif(NOT Git_FOUND)
message(SEND_ERROR "Couldn't find a usable git executable in the environment, and the CMake variable INFOWARE_PCI_IDS_PATH is empty.\n${infoware_pci_ids_error}")
else()
execute_process(COMMAND "${GIT_EXECUTABLE}" clone "${INFOWARE_PCI_IDS_REPOSITORY}" -- pciids
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
RESULT_VARIABLE infoware_git_pciids_clone_err)
endif()
if(infoware_git_pciids_clone_err)
message(SEND_ERROR "Cloning/pulling pciids repository from ${INFOWARE_PCI_IDS_REPOSITORY} failed with ${infoware_git_pciids_clone_err}.\n${infoware_pci_ids_error}")
# Thanks, @griwes
set(infoware_pci_ids_file "${CMAKE_CURRENT_BINARY_DIR}/pciids/pci.ids")
if(EXISTS "${infoware_pci_ids_file}")
execute_process(COMMAND "${GIT_EXECUTABLE}" remote set-url origin "${INFOWARE_PCI_IDS_REPOSITORY}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pciids")
execute_process(COMMAND "${GIT_EXECUTABLE}" pull
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pciids"
RESULT_VARIABLE infoware_git_pciids_clone_err)
else()
execute_process(COMMAND "${GIT_EXECUTABLE}" clone "${INFOWARE_PCI_IDS_REPOSITORY}" -- pciids
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
RESULT_VARIABLE infoware_git_pciids_clone_err)
endif()
if(infoware_git_pciids_clone_err)
message(SEND_ERROR "Cloning/pulling pciids repository from ${INFOWARE_PCI_IDS_REPOSITORY} failed with ${infoware_git_pciids_clone_err}.\n${infoware_pci_ids_error}")
endif()
endif()
endif()

add_executable(infoware_pci_generator tools/pci_generator.cpp)
set_target_properties(infoware_pci_generator PROPERTIES CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF)

set(INFOWARE_PCI_DATA_HPP pci_data.hpp)
set(INFOWARE_PCI_DATA_GEN "infoware_generated/${INFOWARE_PCI_DATA_HPP}")

add_custom_command(OUTPUT ${INFOWARE_PCI_DATA_GEN}
COMMAND ${CMAKE_COMMAND} -E make_directory infoware_generated/
COMMAND $<TARGET_FILE:infoware_pci_generator> "${infoware_pci_ids_file}" > "infoware_generated/pci_data.hpp"
DEPENDS "${infoware_pci_ids_file}"
COMMENT "Generating ${INFOWARE_PCI_DATA_HPP}")

add_custom_target(infoware_generate_pcis DEPENDS "${INFOWARE_PCI_DATA_GEN}")
add_executable(infoware_pci_generator tools/pci_generator.cpp)
set_target_properties(infoware_pci_generator PROPERTIES CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF)

add_custom_command(OUTPUT ${INFOWARE_PCI_DATA_GEN}
COMMAND ${CMAKE_COMMAND} -E make_directory "${INFOWARE_PCI_DATA_DIR}"
COMMAND $<TARGET_FILE:infoware_pci_generator> "${infoware_pci_ids_file}" > "${INFOWARE_PCI_DATA_GEN}"
DEPENDS "${infoware_pci_ids_file}"
COMMENT "Generating ${INFOWARE_PCI_DATA_HPP}")
add_custom_target(infoware_generate_pcis DEPENDS "${INFOWARE_PCI_DATA_GEN}")
else()
include(ExternalProject)
ExternalProject_Add(infoware_generate_pcis
SOURCE_DIR ${CMAKE_SOURCE_DIR}
PREFIX ${CMAKE_BINARY_DIR}/pci_generator
BINARY_DIR ${CMAKE_BINARY_DIR}/pci_generator
BUILD_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target infoware_generate_pcis
INSTALL_COMMAND ""
BUILD_ALWAYS ON
CMAKE_ARGS -DINFOWARE_PCI_DATA_DIR:PATH=${CMAKE_BINARY_DIR}/${INFOWARE_PCI_DATA_DIR})
endif()
add_dependencies(infoware infoware_generate_pcis)


if(MSVC)
# Only CMake 3.15.0 makes this stuff not necessary, but we have a shitty
# minimum required version :/
Expand All @@ -147,7 +157,11 @@ if(WIN32 AND NOT MSVC)
endif()

if(WIN32)
target_link_libraries(infoware PRIVATE gdi32 version Ole32 OleAut32 wbemuuid ntdll)
if(NOT MINGW)
target_link_libraries(infoware PRIVATE gdi32 version Ole32 OleAut32 wbemuuid ntdll)
else()
target_link_libraries(infoware PRIVATE gdi32 version ole32 oleaut32 wbemuuid ntdll)
endif()
endif()


Expand Down
55 changes: 29 additions & 26 deletions src/system/displays/displays_windows.cpp
Expand Up @@ -14,39 +14,42 @@
#include <windows.h>


std::vector<iware::system::display_t> iware::system::displays() {
const struct bundle {
HDC desktop_dc;
std::vector<iware::system::display_t> ret;
} bundle{GetDC(nullptr), {}};
iware::detail::quickscope_wrapper desktop_dc_deleter{[&]() { ReleaseDC(nullptr, bundle.desktop_dc); }};
struct bundle {
HDC desktop_dc;
std::vector<iware::system::display_t> ret;
};

EnumDisplayMonitors(
bundle.desktop_dc, nullptr,
[](auto, auto hdc, auto rect, auto userdata) {
auto& bundle = *reinterpret_cast<struct bundle*>(userdata);
static BOOL CALLBACK consume_one_display(HMONITOR, HDC hdc, LPRECT rect, LPARAM userdata) {
auto& bundle = *reinterpret_cast<struct bundle*>(userdata);

const unsigned int desktop_dpi = GetDeviceCaps(bundle.desktop_dc, LOGPIXELSX);
// https://blogs.msdn.microsoft.com/oldnewthing/20101013-00/?p=12543
const unsigned int desktop_bpp = GetDeviceCaps(bundle.desktop_dc, BITSPIXEL) * GetDeviceCaps(bundle.desktop_dc, PLANES);
const double desktop_refresh_rate = GetDeviceCaps(bundle.desktop_dc, VREFRESH);
const unsigned int desktop_dpi = GetDeviceCaps(bundle.desktop_dc, LOGPIXELSX);
// https://blogs.msdn.microsoft.com/oldnewthing/20101013-00/?p=12543
const unsigned int desktop_bpp = GetDeviceCaps(bundle.desktop_dc, BITSPIXEL) * GetDeviceCaps(bundle.desktop_dc, PLANES);
const double desktop_refresh_rate = GetDeviceCaps(bundle.desktop_dc, VREFRESH);


// Sometimes returns 0 – fall back to the desktop's globals if so.
const unsigned int monitor_dpi = GetDeviceCaps(hdc, LOGPIXELSX);
const unsigned int monitor_bpp = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
const double monitor_refresh_rate = GetDeviceCaps(hdc, VREFRESH);
// Sometimes returns 0 – fall back to the desktop's globals if so.
const unsigned int monitor_dpi = GetDeviceCaps(hdc, LOGPIXELSX);
const unsigned int monitor_bpp = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
const double monitor_refresh_rate = GetDeviceCaps(hdc, VREFRESH);

const unsigned int width = std::abs(rect->right - rect->left);
const unsigned int height = std::abs(rect->bottom - rect->top);
const unsigned int width = std::abs(rect->right - rect->left);
const unsigned int height = std::abs(rect->bottom - rect->top);

// See http://stackoverflow.com/a/12654433/2851815 and up for DPI. In short: can't be done too too well, go with best solution.
bundle.ret.push_back({width, height, monitor_dpi ? monitor_dpi : desktop_dpi, monitor_bpp ? monitor_bpp : desktop_bpp,
monitor_refresh_rate ? monitor_refresh_rate : desktop_refresh_rate});
// See http://stackoverflow.com/a/12654433/2851815 and up for DPI. In short: can't be done too too well, go with best solution.
bundle.ret.push_back({width, height, monitor_dpi ? monitor_dpi : desktop_dpi, monitor_bpp ? monitor_bpp : desktop_bpp,
monitor_refresh_rate ? monitor_refresh_rate : desktop_refresh_rate});

return TRUE;
}

std::vector<iware::system::display_t> iware::system::displays() {
const struct bundle bundle {
GetDC(nullptr), {}
};
iware::detail::quickscope_wrapper desktop_dc_deleter{[&]() { ReleaseDC(nullptr, bundle.desktop_dc); }};

return TRUE;
},
reinterpret_cast<LPARAM>(&bundle));
EnumDisplayMonitors(bundle.desktop_dc, nullptr, &consume_one_display, reinterpret_cast<LPARAM>(&bundle));

return std::move(bundle.ret);
}
Expand Down
14 changes: 14 additions & 0 deletions tools/i686-w64-mingw32.cmake
@@ -0,0 +1,14 @@
set(TOOLCHAIN_PREFIX i686-w64-mingw32)

set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR i686)

set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
set(CMAKE_MC_COMPILER ${TOOLCHAIN_PREFIX}-windmc)
14 changes: 14 additions & 0 deletions tools/x86_64-w64-mingw32.cmake
@@ -0,0 +1,14 @@
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)

set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86_64)

set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
set(CMAKE_MC_COMPILER ${TOOLCHAIN_PREFIX}-windmc)

0 comments on commit 0daefae

Please sign in to comment.