-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Windows native support using MSVC - Visual Studio 2017 #867
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
Conversation
TheJJ
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice work :)
.gitignore
Outdated
| /bin | ||
| /.bin | ||
| build | ||
| deps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
those should probably be /build and /deps, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer disallowing such generic names throughout the repository (I found it useful for embedding thirdparty libraries). I can just make the change here.
buildsystem/check_py_file_list.py
Outdated
| for filename in sorted(listed - actual): | ||
| success = False | ||
| print("file was listed via add_py_module but does not exist: " + | ||
| print("file was listed via add_py_module but does not exist: " + filename + " as " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are those changes relevant or just for your debugging purposes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put them in for my debugging. I left them there because I thought they'd be useful to others too.
| endif() | ||
|
|
||
| if(NOT "${CMAKE_CXX_FLAGS}" MATCHES "-fsanitize") | ||
| if(NOT "${CMAKE_CXX_FLAGS}" MATCHES "-fsanitize" AND NOT MSVC) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so on windows undefined symbols in the libopenage would not throw errors, right? can we somehow display those errors with msvc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused. Undefined symbols would result in link-time errors.
Can you please elaborate what errors we're looking for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undefined symbols are only discovered at link-time for executables, not for libraries like libopenage. Those cflags ensure that errors are shown nevertheless. I guess msvc has something that does the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you confirm or deny if libopenage is actually a shared library (possibly named libopenage.so or libopenage.dylib on other platforms)? If it is a shared library then the linker should complain about any missing symbols. AFAIK VS doesn't have an equivalent of -undefined dynamic_lookup, so no worries there. Otherwise, if it is a static library (like libopenage.a), I'll have to search in the MSVC docs for a flag which can do that, if one exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
openage is and has to be a dynamic library so python can load it (import libopenage). This can never be done for a static library.
On Linux it did not complain, which is why we added those options. Hmm.
| py_get_config_var(LIBDIR PYTHON_LIBRARY_DIR) | ||
| py_get_lib_name(PYTHON_LIBRARY_NAME) | ||
| if (PYTHON STREQUAL PYTHON_EXECUTABLE) | ||
| find_package(PythonLibs REQUIRED) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does PYTHON_EXECUTABLE come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From find_package(PythonInterp <other arguments>) around line 73. Afterwards from the cache.
I'll have to tweak some pieces of this file to make the buildsystem happy on all platforms. You can skip reviewing this file for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This solution is pretty elegant actually, if i understood it correctly :)
Could you please add some comment about the reason behind this? ("If the current python interpreter equals the one found at the very beginning with PythonInterp, we can use the PythonLibs find-module to find the matching libraries. otherwise we ask that interpreter where its matching libraries are", or something like that)
| LINK_LIBRARIES "${PYTHON_LIBRARY_NAME}" | ||
| CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${PYTHON_INCLUDE_DIR}" "-DLINK_DIRECTORIES=${PYTHON_LIBRARY_DIR}" "-DCMAKE_CXX_STANDARD=14" | ||
| LINK_LIBRARIES ${PYTHON_LIBRARIES} | ||
| CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${PYTHON_INCLUDE_DIRS}" "-DCMAKE_CXX_STANDARD=14" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we need the LINK_DIRECTORIES? If the library is in a non-standard path then the lib won't be found. I think that was a problem on mac then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable PYTHON_LIBRARIES has the full path of the libraries (actually just one library per configuration) that need to be linked. I made (rather, tried to make) the variable consistent for other ways to locate the Python interpreter and libraries. I must've missed something that made kevin fail.
| #endif /* libopenage_EXPORTS */ | ||
| #else | ||
| #define LIBOPENAGE_API | ||
| #endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
urghhhnngngngnnggnrhaargrgl. do we really need this pollution of preprocessor macros all over the codebase? what are the alternatives?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK, this is the only way to sanely* link to a DLL('s import library) with C++ interfaces in VS.
The alternatives while still using a shared library include:
- Restricting to C-style interfaces (like extern "C" foo). Then using
LoadLibraryandGetProcAddress(equivalents ofdlopenanddlsymrespectively) for using the DLL at runtime. - Go completely off-book and implement mangling for C++ identifiers (which is bound to break in the next release of VS).
Another alternative is to change libopenage to a static library - the problem would be it'll be linked to every python extension (.pyd) we build - bloating up the package when we build one.
Usually this macro doesn't scatter as much if the interface is small and consolidated. In our case, the interface with python is spread across the library.
*Sanity is relative. Essentially an alien concept to VS users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay...
Is it common practice to name this ${LIBNAME}_API? Otherwise I'd suggest we use some "simpler" name, e.g. OAAPI, OAFUNC, or some idea of yours so it's less text pollution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently it isn't. I don't think there's a large enough convention to follow out there. I used what I knew from experience. I'm certainly open to using OAAPI as that strikes a nice balance between a largsmaller and a descriptive name. OAFUNC, not so much, because this macro is used for classes and functions alike (actually even for externed objects, but I don't know what common name all of them can use). If you're okay with OAAPI, I can just do a find-replace all.
| * wraps an existing FD | ||
| */ | ||
| FD(int fd=STDOUT_FILENO); | ||
| FD(int fd); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the problem here? Does msvc have problems with default argument values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really. Just with STDOUT_FILENO. Usually, it's defined in unistd.h which is just absent for VS. Turned out #define STDOUT_FILENO 1 was too much to ask for.
| entry, | ||
| os.path.dirname(self.name_data_file) | ||
| ) | ||
| ).replace(os.path.sep, '/') # HACK: Change to better path handling |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no fear, this will totally be dropped with nyan.
| #include <mutex> | ||
| #include <condition_variable> | ||
|
|
||
| #include <epoxy/gl.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GUI code must not depend on epoxy.
| #include "gui_renderer_impl.h" | ||
|
|
||
| #include <cassert> | ||
| #include <ciso646> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never seen this header in the wild.
If it's about the and and or operators then it's better to replace them with the C++ operators.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
http://en.cppreference.com/w/cpp/language/operator_alternative
Because in C++ these are built into the language, the C++ version of
<iso646.h>, as well as<ciso646>, does not define anything.
-> no need to replace them with symbol operators and no need to include the header
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
http://en.cppreference.com/w/cpp/header/ciso646
... in a conforming implementation this header is empty.
It may still be required in order to have the alternative operator representations in old or non-conformant compilers.
And you would've guessed it already, MSVC is non-conforming at least in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
| #else | ||
| #include <OpenGL/gl.h> | ||
| #endif | ||
| #include <epoxy/gl.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GUI code must not depend on epoxy.
Tomatower
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing work, just a few details!
| if (reversed) { | ||
| for (size_t idx = this->stack_addrs.size(); idx > 0; idx--) { | ||
| // `for (auto pc : this->stack_addrs | <ranges-ns>::view::reverse)` after Ranges-TS | ||
| for (size_t idx = this->stack_addrs.size(); idx-- > 0;) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you do the for like that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The next line does a dereference using idx. I was initially planning to use a reverse iterator, but then got a hint from line 181 above to make a smaller change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you could leave the for as-is (for (size_t idx = this->stack_addrs.size(); idx > 0; idx--) {), and we wait util we have the reverse iterator?
|
|
||
| namespace { | ||
| void callback(GLenum source, GLenum, GLuint, GLenum, GLsizei, const GLchar *message, const void*) { | ||
| void APIENTRY callback(GLenum source, GLenum, GLuint, GLenum, GLsizei, const GLchar *message, const void*) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
APIENTRY is not defined in a linux environment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It must be (I'm assuming) in epoxy/gl.h. I was relying on the CI reports to ensure that it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did not knew that. You are right that CI will see such things.
|
|
||
| #include "program.h" | ||
|
|
||
| #include <unistd.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we prefer to surround it with #ifndef _MSC_VER
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used that option only as a last-resort thing. The first (and IMO better) option is to identify and eliminate platform-dependent dependencies like this (technically unistd.h is part of the POSIX standard, but VS doesn't provide one). Same as above, if the CI is happy, we can remove this, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you, to eliminate such dependencies is best.
libopenage/error/error.h
Outdated
|
|
||
| // ENSURE(condition, errormessage << variable << etcetc) | ||
| #define ENSURE(...) do if (unlikely(not OPENAGE_ENS_FIRST(__VA_ARGS__))) throw ::openage::error::Error(MSG(err) OPENAGE_ENS_REST(__VA_ARGS__)); while (0) | ||
| // TODO: Switch to variadic template if needed (or drop the variadic behaviour, if acceptable) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may or may not be a macro.
Calling it with just one parameter (the 'condition') should produce a compiler warning.
| #ifndef __APPLE__ | ||
| #ifdef _MSC_VER | ||
| #define NOMINMAX | ||
| #include <windows.h> // for WINGDIAPI, APIENTRY |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The libopenage/gui/guisys deals only with Qt and SDL. It doesn't include anything else from openage or its dependencies like epoxy. The openage/libopenage/gui/integration (and openage/libopenage/gui/integration/private/gui_make_standalone_subtexture.h in it) is for connecting together Qt and openage, hence it uses epoxy that's used by openage textures.
This #ifdef boilerplate can be probably fixed by including some GL Qt header in gui_renderer.cpp file before the #include "gui_renderer.h". Qt basically does the same thing as epoxy.
ef51e64 to
f2f2af3
Compare
| #else | ||
| #include <OpenGL/gl.h> | ||
| #endif | ||
| #include <QtGui/qopengl.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't really see the QtGui/qopengl.h in the Qt docs. It's probably more like a private header. I remember that I used #include <QOpenGLFunctions> somewhere instead.
The other thing is that the gui_renderer.h is a pimpl wrapper to isolate the openage code from Qt. So it can't include any Qt stuff. I can't try it right now, but that include should work in the gui_renderer.cpp.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A Qt examples page shows that it can be used directly [Sorry, they don't have line numbers; and I don't know the protocol for sharing their code without involving the copyrights/licences]. Given, I used a more explicit full path - which I can change to the shorter one if needed. OTOH, QOpenGLFunctions provides some wrappers which aren't required. I'm not well versed with Qt to take a decision either way.
I observed the pimpl idiom used in the gui code (here and in a few other places). For the inclusion of decided-upon file in gui_renderer.cpp:
Option 0: Before gui_renderer.h directly contradicts mom's recommendation. I'd prefer not to do that.
Option 1: After gui_renderer.h results in compilation failure for all units including it (error C3646: 'render': unknown override specifier and some others). ❌
Option (try larger change): Change/remove the GuiRenderer::render member to make it work with a forward-declared type GLuint. I'll need more information to make this work.
Option (none of these): Revert back to the expanded form before my last change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Second best for me is the 'expanded form'.
TheJJ
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're getting there :)
It would be very good for other windows guys if you added some kind of introduction how the visualstudio project is generated so they can easily contribute. Maybe in doc/ide.md (or turn it into a folder so we have doc/ide/qtcreator.md and doc/ide/visualstudio.md)?
| py_get_config_var(LIBDIR PYTHON_LIBRARY_DIR) | ||
| py_get_lib_name(PYTHON_LIBRARY_NAME) | ||
| if (PYTHON STREQUAL PYTHON_EXECUTABLE) | ||
| find_package(PythonLibs REQUIRED) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This solution is pretty elegant actually, if i understood it correctly :)
Could you please add some comment about the reason behind this? ("If the current python interpreter equals the one found at the very beginning with PythonInterp, we can use the PythonLibs find-module to find the matching libraries. otherwise we ask that interpreter where its matching libraries are", or something like that)
| if (reversed) { | ||
| for (size_t idx = this->stack_addrs.size(); idx > 0; idx--) { | ||
| // `for (auto pc : this->stack_addrs | <ranges-ns>::view::reverse)` after Ranges-TS | ||
| for (size_t idx = this->stack_addrs.size(); idx-- > 0;) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you could leave the for as-is (for (size_t idx = this->stack_addrs.size(); idx > 0; idx--) {), and we wait util we have the reverse iterator?
libopenage/error/stackanalyzer.cpp
Outdated
| } | ||
|
|
||
| // TODO: exact copy of the GNU execinfo counterpart below. Move to common place. | ||
| void StackAnalyzer::get_symbols(std::function<void (const backtrace_symbol *)> cb, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you want to address this now? it would just require some preprocessor adjustments? or should we do it later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the changes.
| std::string demangle(const char *symbol) { | ||
| #ifdef _MSC_VER | ||
| // TODO: demangle names for MSVC; | ||
| return symbol; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an msvc demangling abi function? if yes, can you please add it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is: UnDecorateSymbolName. However, it has a problem mentioned in the Remarks section: it is single threaded. I can make this work with some synchronization primitives, but I'd prefer that to be in a subsequent PR, so the focus here remains on the build and we can get more opinions before going that way.
Suggestions?
|
|
||
| std::string symbol_name(const void *addr, bool require_exact_addr, bool no_pure_addrs) { | ||
| #ifdef _MSC_VER | ||
| return no_pure_addrs ? "" : addr_to_string(addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the symbol name resolution is missing, how much effort is it to add that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to above (although, clearly I forgot to add a TODO - I'll do that).
There's SymFromAddr, which has the same pitfalls as the one mentioned above.
This problem is actually discussed in #480, and I would like to know their opinions on using this approach.
| #define unlikely(x) __builtin_expect(!!(x), 0) | ||
| #else | ||
| #define likely(x) (x) | ||
| #define unlikely(x) (x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't msvc have branch preduction tuning?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually took it from a cython generated cpp file:
/* Test for GCC > 2.95 */
#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)))
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else /* !__GNUC__ or GCC < 2.95 */
#define likely(x) (x)
#define unlikely(x) (x)
#endif /* __GNUC__ */
I'm not aware of a branch prediction tuning feature for MSVC, if one exists.
| #endif /* libopenage_EXPORTS */ | ||
| #else | ||
| #define LIBOPENAGE_API | ||
| #endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay...
Is it common practice to name this ${LIBNAME}_API? Otherwise I'd suggest we use some "simpler" name, e.g. OAAPI, OAFUNC, or some idea of yours so it's less text pollution.
libopenage/util/compiler.h
Outdated
|
|
||
| #if defined(_MSC_VER) | ||
| #ifndef HAVE_SSIZE_T | ||
| typedef int ssize_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm I think that is not correct, as int is not always the size of size_t.
The type
ssize_tshall be capable of storing values at least in the range[-1, {SSIZE_MAX}].
Strictly speaking, we've used ssize_t wrong in some places in codebase, so we should fix that someday :)
On my machine SSIZE_MAX is defined as LONG_MAX, which is 2 ** 63 - 1, and bigger than int (2 ** 31 - 1).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. And I'd like nothing more than a (POSIX?) standard file providing this declaration.
For instance, MSVC claims to provide SSIZE_T in BaseTsd.h. My problem with that, however, is with a disagreeing [re]definition from pyconfig.h. So I went with a non-conflicting definition, and wrapped it in _MSC_VER preprocessor guards. To be completely honest, I haven't even tried building this code for x64 yet. That would be another error to deal with.
I can check if we can reduce the usages of ssize_t. But, we would still need a definition that agrees with Python's headers, otherwise it could lead to other problems in the build.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, the ssize_t is 32 bit wide from python because of your 32 bit platform i guess. So if we define it the way python does, it should be fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Python's headers make it bad to use as an exact copy:
/* _W64 is not defined for VC6 or eVC4 */
#ifndef _W64
#define _W64
#endif
/* Define like size_t, omitting the "unsigned" */
#ifdef MS_WIN64
typedef __int64 ssize_t;
#else
typedef _W64 int ssize_t;
#endifWhere MS_WIN64 is defined if another macro (_WIN64) is defined. I just made my definition work with the x86 compilation; For x64, I'll probably use the other definition and _WIN64 directly. Is that okay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, if there's no direct way, then so be it. But it seems strange that such definitions are necessary. Should be part of the standard library.
5df96d5 to
06773eb
Compare
Tweak to find python library Fix inplacemodules for msvc build
Updates for MSVC build
Consolidate compiler specific attributes into macros Reduce/remove usage of unistd.h Define ssize_t appropriately for Windows Introduce `OAAPI` for decorating DLL entry points Reduce CONCAT and LOOP macros argument count
introduce `OAAPI`
TheJJ
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking very good now!
A step towards #9.
Fixes #508 with a modification - VS2017 instead of VS2015.
Supersedes #582 (credits to @YellowOnion).
## The procedure (this is here for my recollection later) - Get the dependencies using `vcpkg`. - Build/install the missing dependency `opusfile` manually. - Copy `dirent.h` from `vcpkg`'s downloads directory - it's named `fontconfig-dirent.h`. - Build using CMake - the usual workflow. - Install the `DejaVu Serif Book` font and copy the configuration to the fontconfig directory. - Modify the environment variables required to make the program run (hacks required before proper packaging).A summary of the changes
_MSC_VERor_WIN32. The former for MSVC specific code, and the latter if it is applicable to other compilers on Windows also.LIBOPENAGE_APIOAAPIfor decorating the DLL's entry points for Windows.__declspec(dllexport)when compiling the DLL's sources,__declspec(dllimport)for the code including the header files only - the API user.doc/code/pyinterface.md.[Disrupting change] Inlibopenage/error/error.h, the variadic macroENSUREhas been changed to a two-argument macro. I left aTODO- kindly respond with the approach to choose here.'\\'(weird, agreed).libopenage/error/stackanalyzer.cppcontains the skeleton code for Missing StackAnalyzer implementation for WIN32 #479. Without Missing util/compiler implementation for WIN32 #480 though, I don't expect it to provide a lot of useful information. The change includes a bug-fix in the GNU execinfo section.ciso646which provides the expansion forand,or,not,xor, etc.doc/build_instructions/windows_msvc.md.I've left a bunch of
TODOs andHACKs around in the code. I can try to address the critical ones pointed out by the reviewers, the rest can be addressed subsequently.I've built the project on Windows (using MSVC) only. I'll rely on the CI reports for other platforms (apologies for the cache thrashing). Please let me know if I need to run some test manually.