Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CMake, MinGW64 and MSVC 2013 build #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ x64
.vs

# imgui
imgui.ini
imgui.ini

# build
.cache/
build*/
install*/
36 changes: 36 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.0)
# Consider if MSVC, cross-compile MinGW or MinGW with explicit toolchain path provided as -DTOOLCHAIN_ROOT=<path-to-mingw-bin-folder-with-trailing-slash>
if(NOT (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows") OR TOOLCHAIN_ROOT)
if(NOT TOOLCHAIN_ROOT)
set(TOOLCHAIN_ROOT /usr/bin/)
endif()
set(TOOLCHAIN_PREFIX ${TOOLCHAIN_ROOT}x86_64-w64-mingw32)
include(MinGW64.cmake)
endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

project(triangleBin LANGUAGES CXX)

file(GLOB SOURCES_MAIN *.cpp)
file(GLOB_RECURSE SOURCES_IMGUI imgui/*.cpp)
file(GLOB SHADERS *.hlsl)
set(SOURCES ${SOURCES_IMGUI} ${SOURCES_MAIN})

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(${PROJECT_NAME} ${SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC imgui)
target_link_libraries(${PROJECT_NAME} PUBLIC dxgi d3d11 d3dcompiler imm32)
install(FILES ${SHADERS} DESTINATION .)
install(TARGETS ${PROJECT_NAME} DESTINATION .)

if(NOT MSVC)
target_compile_definitions(${PROJECT_NAME} PUBLIC WINVER=0x0600 _WIN32_WINNT=0x0600)
if(CMAKE_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_HAVE_LIBC_PTHREAD EQUAL 1 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13) # refine if needed: MinGW GCC8 and 10 needs it, MinGW GCC13 not, MinGW Clang 16 provides std::threads / std::mutex, so not considered
option(MINGW_STDTHREADS_GENERATE_STDHEADERS "" ON)
add_subdirectory(mingw-std-threads)
target_link_libraries(${PROJECT_NAME} PUBLIC mingw_stdthreads)
endif()
endif()
32 changes: 32 additions & 0 deletions MinGW64.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# source: https://gist.github.com/peterspackman/8cf73f7f12ba270aa8192d6911972fe8

# Sample toolchain file for building for Windows from an Ubuntu Linux system.
#
# Typical usage: *) install cross compiler: `sudo apt-get install mingw-w64` *)
# cd build *) cmake -DCMAKE_TOOLCHAIN_FILE=~/mingw-w64-x86_64.cmake .. This is
# free and unencumbered software released into the public domain.

if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
set(EXE_EXTENSION .exe)
else()
set(EXE_EXTENSION)
endif()
set(CMAKE_SYSTEM_NAME Windows)

# cross compilers to use for C, C++ and Fortran
set(CMAKE_ASM_COMPILER ${TOOLCHAIN_PREFIX}-gcc${EXE_EXTENSION})
set(CMAKE_C_COMPILER_AR ${TOOLCHAIN_PREFIX}-ar${EXE_EXTENSION})
set(CMAKE_C_COMPILER_RANLIB ${TOOLCHAIN_PREFIX}-ranlib${EXE_EXTENSION})
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc${EXE_EXTENSION})
set(CMAKE_CXX_COMPILER_AR ${TOOLCHAIN_PREFIX}-ar${EXE_EXTENSION})
set(CMAKE_CXX_COMPILER_RANLIB ${TOOLCHAIN_PREFIX}-ranlib${EXE_EXTENSION})
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++${EXE_EXTENSION})
set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran${EXE_EXTENSION})
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres${EXE_EXTENSION})
# target environment on the build host system
set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_PREFIX})

# modify default behavior of FIND_XXX() commands
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
4 changes: 2 additions & 2 deletions dxutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ std::string MultiByteFromWide(const std::wstring& ws)
std::string MultiByteFromHR(HRESULT hr)
{
_com_error err(hr);
return MultiByteFromWide(err.ErrorMessage());
return MultiByteFromWide(WideFromMultiByte(err.ErrorMessage()));
}

bool detail_CheckHR(HRESULT hr, const char* file, const char* function, int line)
Expand All @@ -71,7 +71,7 @@ bool detail_CheckHR(HRESULT hr, const char* file, const char* function, int line
L"File: " + wfile + L"\n" +
L"Function: " + wfunction + L"\n" +
L"Line: " + std::to_wstring(line) + L"\n" +
L"ErrorMessage: " + err.ErrorMessage() + L"\n";
L"ErrorMessage: " + WideFromMultiByte(err.ErrorMessage()) + L"\n";

int result = MessageBoxW(NULL, msg.c_str(), L"Error", MB_ABORTRETRYIGNORE);
if (result == IDABORT)
Expand Down
16 changes: 12 additions & 4 deletions dxutil.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#pragma once

#ifndef NOMINMAX
#define NOMINMAX
#endif
#define WIN32_LEAN_AND_MEAN
#include <Windowsx.h>
#include <windowsx.h>
#undef GetWindowFont // because imgui
#include <ShellScalingApi.h>
#include <shellscalingapi.h>
#include <d3d11.h>
#include <dxgi1_4.h>
#include <wrl/client.h>

#include <string>
Expand All @@ -25,5 +26,12 @@ void SimpleMessageBox_FatalError(const char* fmt, ...);
bool detail_CheckHR(HRESULT hr, const char* file, const char* function, int line);
bool detail_CheckWin32(BOOL okay, const char* file, const char* function, int line);

#if defined(_MSC_VER)
#define CHECKHR(hr) detail_CheckHR(hr, __FILE__, __FUNCSIG__, __LINE__)
#define CHECKWIN32(okay) detail_CheckWin32(okay, __FILE__, __FUNCSIG__, __LINE__)
#define CHECKWIN32(okay) \
detail_CheckWin32(okay, __FILE__, __FUNCSIG__, __LINE__)
#else
#define CHECKHR(hr) detail_CheckHR(hr, __FILE__, __FUNCTION__, __LINE__)
#define CHECKWIN32(okay) \
detail_CheckWin32(okay, __FILE__, __FUNCTION__, __LINE__)
#endif
6 changes: 3 additions & 3 deletions imgui/imgui_impl_dx11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,9 +389,9 @@ bool ImGui_ImplDX11_CreateDeviceObjects()

// Create the input layout
D3D11_INPUT_ELEMENT_DESC local_layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)(size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)(size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)(size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
return false;
Expand Down
14 changes: 3 additions & 11 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void WindowInit(int width, int height, const char* title)
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandleW(NULL);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
wc.lpszClassName = L"WindowClass";
CHECKWIN32(RegisterClassExW(&wc));

Expand Down Expand Up @@ -92,7 +92,7 @@ void RendererInit()
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = g_hWnd;
scd.Windowed = TRUE;
scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;

UINT flags = 0;
Expand All @@ -102,12 +102,9 @@ void RendererInit()

ComPtr<ID3D11Device> pDevice;
ComPtr<ID3D11DeviceContext> pDeviceContext;
ComPtr<IDXGISwapChain2> pSwapChain;
HANDLE hFrameLatencyWaitableObject;
ComPtr<IDXGISwapChain> pSwapChain;

D3D_FEATURE_LEVEL kFeatureLevels[] = {
D3D_FEATURE_LEVEL_12_1,
D3D_FEATURE_LEVEL_12_0,
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
Expand Down Expand Up @@ -137,7 +134,6 @@ void RendererInit()
(featureLevel >> 12) & 0x0F, (featureLevel >> 8) & 0x0F);
}

hFrameLatencyWaitableObject = pSwapChain->GetFrameLatencyWaitableObject();
CHECKHR(pDXGIFactory->MakeWindowAssociation(g_hWnd, DXGI_MWA_NO_WINDOW_CHANGES));

g_Device = pDevice.Get();
Expand All @@ -146,7 +142,6 @@ void RendererInit()
g_DeviceContext->AddRef();
g_SwapChain = pSwapChain.Get();
g_SwapChain->AddRef();
g_FrameLatencyWaitableObject = hFrameLatencyWaitableObject;
}

void RendererResize(int width, int height)
Expand All @@ -168,9 +163,6 @@ void RendererPaint()
ID3D11DeviceContext* dc = g_DeviceContext;
IDXGISwapChain* sc = g_SwapChain;

// Wait until the previous frame is presented before drawing the next frame
CHECKWIN32(WaitForSingleObject(g_FrameLatencyWaitableObject, INFINITE) == WAIT_OBJECT_0);

// grab the current backbuffer
ComPtr<ID3D11Texture2D> pBackBufferTex2D;
ComPtr<ID3D11RenderTargetView> pBackBufferRTV;
Expand Down
35 changes: 35 additions & 0 deletions mingw-std-threads/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
project(mingw_stdthreads)
cmake_minimum_required(VERSION 3.0)

option(MINGW_STDTHREADS_BUILD_TEST "Build tests")
option(MINGW_STDTHREADS_GENERATE_STDHEADERS "Generate std-like headers")

string(CONCAT mingw_stdthreads_dir_docstring
"Optional. When generating std-like headers , this variable can be set"
"to manually specify the path to mingw-stdthreads directory containing"
"original library headers.")
set(MINGW_STDTHREADS_DIR "${PROJECT_SOURCE_DIR}"
CACHE PATH ${mingw_stdthreads_dir_docstring})

# mingw-stdthreads is a header-only library, so make it a INTERFACE target
add_library(${PROJECT_NAME} INTERFACE)
target_include_directories(${PROJECT_NAME} INTERFACE "${PROJECT_SOURCE_DIR}")

if(MINGW_STDTHREADS_GENERATE_STDHEADERS)
# Check if we are using gcc or clang
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
# Add as dependency and generate std headers
add_subdirectory(cmake_stdheaders_generator)
target_link_libraries(${PROJECT_NAME} INTERFACE
cmake_stdheaders_generator)
else()
message(WARNING "Cannot generate std headers with this compiler: "
${CMAKE_CXX_COMPILER_ID} ". "
"Please fall back to #include <mingw.xxx.h>")
endif()
endif()

# Build tests.exe
if(MINGW_STDTHREADS_BUILD_TEST)
add_subdirectory(tests)
endif()
24 changes: 24 additions & 0 deletions mingw-std-threads/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Copyright (c) 2016, Mega Limited
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

60 changes: 60 additions & 0 deletions mingw-std-threads/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
mingw-std-threads
=================

Implementation of standard C++11 threading classes, which are currently still missing on MinGW GCC.

Target Windows version
----------------------
This implementation should work with Windows XP (regardless of service pack), or newer.
The library automatically detects the version of Windows that is being targeted (at compile time), and selects an implementation that takes advantage of available Windows features.
In MinGW GCC, the target Windows version may optionally be selected by the command-line option `-D _WIN32_WINNT=...`.
Use `0x0600` for Windows Vista, or `0x0601` for Windows 7.
See "[Modifying `WINVER` and `_WIN32_WINNT`](https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt)" for more details.

Usage
-----

This is a header-only library. To use, just include the corresponding `mingw.xxx.h file`, where `xxx` would be the name of the standard header that you would normally include.

For example, `#include "mingw.thread.h"` replaces `#include <thread>`.

A `CMakeLists.txt` has also been provided. You can add it to your project by using `add_subdirectory()`, and then this library can be added as your targets' dependency by using `target_link_libraries(YOUR_TARGET PRIVATE mingw_stdthreads)`. By default it just adds a include path, allowing you to include headers using angle brackets (for example `#include <mingw.thread.h>`). But you can also provide options to let it generate "std-like" headers (see next paragraph).

Using "std-like" headers
------------------------

Probably you don't really want to replace all your includes from `#include <header>` to `#include "mingw.header.h"`. So if you are using GCC or clang, here are some ways to make you happy :)

With CMake, you just need to turn on the option `MINGW_STDTHREADS_GENERATE_STDHEADERS` before adding mingw-stdthreads, something like this:
```CMake
option(MINGW_STDTHREADS_GENERATE_STDHEADERS "" ON)
add_subdirectory(mingw_stdthreads)
target_link_libraries(${TARGET} PRIVATE mingw_stdthreads)
```
When CMake generates project files, headers named in the "standard header" way will be generated and added to your include path. Then you can avoid stuffs like `mingw.thread.h`, and keep using `#include <thread>` like always. In addition, `MINGW_STDTHREADS_GENERATED_STDHEADERS` will be defined, you can use this macro to check if those generated headers are actually available.

If you aren't using CMake, you can use one of the three scripts inside [utility_scripts](utility_scripts) directory to manually generate those "std-like" headers. Note that this requires Microsoft Power Shell, so if you are cross-compiling, you would need to install Power Shell.

Compatibility
-------------

This code has been tested to work with MinGW-w64 5.3.0, but should work with any other MinGW version that has the `std` threading classes missing, has C++11 support for lambda functions, variadic templates, and has working mutex helper classes in `<mutex>`.

Switching from the win32-pthread based implementation
-----------------------------------------------------
It seems that recent versions of MinGW-w64 include a Win32 port of pthreads, and have the `std::thread`, `std::mutex`, etc. classes implemented and working based on that compatibility layer.

You could use the built-in pthread implementation of Mingw by using the posix compiler, eg: `x86_64-w64-mingw32-g++-posix` (for Windows 64-bit).

That is a somewhat heavier implementation, as it relies on an abstraction layer, so you may still want to use this implementation for efficiency purposes.
Unfortunately you can't use this library standalone and independent of the system `<mutex>` headers, as it relies on those headers for `std::unique_lock` and other non-trivial utility classes.
In that case you will need to edit the `c++-config.h` file of your MinGW setup and comment out the definition of _GLIBCXX_HAS_GTHREADS.
This will cause the system headers not to define the actual `thread`, `mutex`, etc. classes, but still define the necessary utility classes.

Why MinGW has no threading classes
----------------------------------
It seems that for cross-platform threading implementation, the GCC standard library relies on the gthreads/pthreads library.
If this library is not available, as is the case with MinGW, the classes `std::thread`, `std::mutex`, `std::condition_variable` are not defined.
However, various usable helper classes are still defined in the system headers.
Hence, this implementation does not re-define them, and instead includes those headers.

Loading