From 9301dec98df7a7f694e253ab63753659aeaa7bbc Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 28 Nov 2016 04:16:18 +0000 Subject: [PATCH] Use the same code for loading resources in all executables. All of our executables need resources; e.g. the vector font is a resource and it is necessary for generation. Before this commit, the GUI executable loaded the resources in a nice way, and everything else did it in a very ad-hoc, fragile way. After this commit, all executables are placed in /bin and follow the same algorithm: * On Windows, resources are compiled and linked into every executable. * On Linux, resources are copied into /res (which is tried first) and /share/solvespace (which is tried second). * On macOS, resources are copied into /res (which is tried first) and /bin/solvespace.app/Contents/Resources (which is tried second). In practice this means that we can add as many executables as we want without duplicating lots of code. In addition, on macOS, we can place supplementary executables into the bundle, and they can use resources from the bundle transparently. --- CMakeLists.txt | 3 ++ README.md | 8 +-- appveyor.yml | 10 ++-- bench/CMakeLists.txt | 6 ++- bench/harness.cpp | 58 +-------------------- res/CMakeLists.txt | 19 ++++--- src/CMakeLists.txt | 12 +++-- src/lib.cpp | 2 +- src/platform/cocoamain.mm | 26 +-------- src/platform/gtkmain.cpp | 70 ------------------------- src/platform/headless.cpp | 25 --------- src/platform/unixutil.cpp | 107 +++++++++++++++++++++++++++++++++++++- src/platform/w32main.cpp | 12 +---- src/platform/w32util.cpp | 19 ++++++- src/solvespace.h | 2 +- test/CMakeLists.txt | 6 ++- test/harness.cpp | 20 +++---- 17 files changed, 175 insertions(+), 230 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c858d4c3..970e4039 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,9 @@ if(NOT WIN32 AND NOT APPLE) set(GUI gtk2 CACHE STRING "GUI toolkit to use (one of: gtk2 gtk3)") endif() +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) + if(NOT CMAKE_C_COMPILER_ID STREQUAL CMAKE_CXX_COMPILER_ID) message(FATAL_ERROR "C and C++ compilers should be supplied by the same vendor") endif() diff --git a/README.md b/README.md index 40fffc5a..fa8a96e8 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ After that, build SolveSpace as following: make sudo make install -The application is built as `build/src/solvespace`. +The application is built as `build/bin/solvespace`. A fully functional port to GTK3 is available, but not recommended for use due to bugs in this toolkit. @@ -77,7 +77,7 @@ Or, build 64-bit SolveSpace as following: -DENABLE_TESTS=OFF make -The application is built as `build/src/solvespace.exe`. +The application is built as `build/bin/solvespace.exe`. Space Navigator support will not be available. @@ -103,8 +103,8 @@ After that, build SolveSpace as following: cmake .. -DENABLE_TESTS=OFF make -The application is built in `build/src/solvespace.app`, and -the executable file is `build/src/solvespace.app/Contents/MacOS/solvespace`. +The application is built in `build/bin/solvespace.app`, and +the executable file is `build/bin/solvespace.app/Contents/MacOS/solvespace`. [homebrew]: http://brew.sh/ diff --git a/appveyor.yml b/appveyor.yml index 8d839946..5533b176 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,15 +11,11 @@ build_script: - msbuild "src\solvespace.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - msbuild "test\solvespace_testsuite.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" test_script: - - test\%BUILD_TYPE%\solvespace_testsuite.exe + - bin\%BUILD_TYPE%\solvespace_testsuite.exe artifacts: - - path: build\src\Debug\solvespace.exe + - path: build\bin\%BUILD_TYPE%\solvespace.exe name: solvespace.exe - - path: build\src\Debug\solvespace.pdb - name: solvespace.pdb - - path: build\src\RelWithDebInfo\solvespace.exe - name: solvespace.exe - - path: build\src\RelWithDebInfo\solvespace.pdb + - path: build\bin\%BUILD_TYPE%\solvespace.pdb name: solvespace.pdb deploy: # Releases to solvespace/solvespace diff --git a/bench/CMakeLists.txt b/bench/CMakeLists.txt index 9531820e..18e57364 100644 --- a/bench/CMakeLists.txt +++ b/bench/CMakeLists.txt @@ -6,7 +6,11 @@ foreach(pkg_config_lib CAIRO) endforeach() add_executable(solvespace_benchmark - harness.cpp) + harness.cpp + $) target_link_libraries(solvespace_benchmark solvespace_headless) + +add_dependencies(solvespace_benchmark + resources) diff --git a/bench/harness.cpp b/bench/harness.cpp index bdae4697..cb2367cb 100644 --- a/bench/harness.cpp +++ b/bench/harness.cpp @@ -4,55 +4,6 @@ // Copyright 2016 whitequark //----------------------------------------------------------------------------- #include "solvespace.h" -#if defined(WIN32) -#include -#else -#include -#endif - -namespace SolveSpace { - // These are defined in headless.cpp, and aren't exposed in solvespace.h. - extern std::string resourceDir; -} - -static std::string ResourceRoot() { - static std::string rootDir; - if(!rootDir.empty()) return rootDir; - - // No especially good way to do this, so let's assume somewhere up from - // the current directory there's our repository, with CMakeLists.txt, and - // pivot from there. -#if defined(WIN32) - wchar_t currentDirW[MAX_PATH]; - GetCurrentDirectoryW(MAX_PATH, currentDirW); - rootDir = Narrow(currentDirW); -#else - rootDir = "."; -#endif - - // We're never more than four levels deep. - for(size_t i = 0; i < 4; i++) { - std::string listsPath = rootDir; - listsPath += PATH_SEP; - listsPath += "CMakeLists.txt"; - FILE *f = ssfopen(listsPath, "r"); - if(f) { - fclose(f); - rootDir += PATH_SEP; - rootDir += "res"; - return rootDir; - } - - if(rootDir[0] == '.') { - rootDir += PATH_SEP; - rootDir += ".."; - } else { - rootDir.erase(rootDir.rfind(PATH_SEP)); - } - } - - ssassert(false, "Couldn't locate repository root"); -} static bool RunBenchmark(std::function setupFn, std::function benchFn, @@ -90,14 +41,7 @@ static bool RunBenchmark(std::function setupFn, } int main(int argc, char **argv) { -#if defined(_MSC_VER) - _set_abort_behavior(0, _WRITE_ABORT_MSG); -#endif -#if defined(WIN32) - InitHeaps(); -#endif - - resourceDir = ResourceRoot(); + InitPlatform(); std::string mode, filename; if(argc == 3) { diff --git a/res/CMakeLists.txt b/res/CMakeLists.txt index c87a4921..216b4276 100644 --- a/res/CMakeLists.txt +++ b/res/CMakeLists.txt @@ -30,18 +30,23 @@ if(WIN32) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${source}") endfunction() elseif(APPLE) - set(app_resource_dir ${CMAKE_BINARY_DIR}/src/solvespace.app/Contents/Resources) + set(app_resource_dir ${CMAKE_BINARY_DIR}/bin/solvespace.app/Contents/Resources) + set(cli_resource_dir ${CMAKE_BINARY_DIR}/res) function(add_resource name) set(source ${CMAKE_CURRENT_SOURCE_DIR}/${name}) - set(target ${app_resource_dir}/${name}) - set(resource_list "${resource_list};${target}" PARENT_SCOPE) + set(target_app ${app_resource_dir}/${name}) + set(target_cli ${cli_resource_dir}/${name}) + set(resource_list "${resource_list};${target_app};${target_cli}" PARENT_SCOPE) - get_filename_component(target_dir ${target} DIRECTORY) + get_filename_component(target_app_dir ${target_app} DIRECTORY) + get_filename_component(target_cli_dir ${target_cli} DIRECTORY) add_custom_command( - OUTPUT ${target} - COMMAND ${CMAKE_COMMAND} -E make_directory ${target_dir} - COMMAND ${CMAKE_COMMAND} -E copy ${source} ${target} + OUTPUT ${target_app} ${target_cli} + COMMAND ${CMAKE_COMMAND} -E make_directory ${target_app_dir} + COMMAND ${CMAKE_COMMAND} -E copy ${source} ${target_app} + COMMAND ${CMAKE_COMMAND} -E make_directory ${target_cli_dir} + COMMAND ${CMAKE_COMMAND} -E copy ${source} ${target_cli} COMMENT "Copying resource ${name}" DEPENDS ${source} VERBATIM) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7880c3bc..91cfe792 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,6 +20,11 @@ else() platform/unixutil.cpp) endif() +if(APPLE) + set(util_LIBRARIES + ${APPKIT_LIBRARY}) +endif() + # libslvs set(libslvs_SOURCES @@ -45,6 +50,9 @@ target_compile_definitions(slvs target_include_directories(slvs PUBLIC ${CMAKE_SOURCE_DIR}/include) +target_link_libraries(slvs + ${util_LIBRARIES}) + set_target_properties(slvs PROPERTIES PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/include/slvs.h VERSION ${solvespace_VERSION_MAJOR}.${solvespace_VERSION_MINOR} @@ -101,9 +109,6 @@ elseif(APPLE) set(platform_BUNDLED_LIBS ${PNG_LIBRARIES} ${FREETYPE_LIBRARIES}) - - set(platform_LIBRARIES - ${APPKIT_LIBRARY}) elseif(HAVE_GTK2 OR HAVE_GTK3) set(platform_SOURCES platform/gtkmain.cpp @@ -192,6 +197,7 @@ add_library(solvespace_cad STATIC target_link_libraries(solvespace_cad dxfrw + ${util_LIBRARIES} ${ZLIB_LIBRARY} ${PNG_LIBRARY} ${FREETYPE_LIBRARY} diff --git a/src/lib.cpp b/src/lib.cpp index 8a4bdf09..d9abe3c7 100644 --- a/src/lib.cpp +++ b/src/lib.cpp @@ -81,7 +81,7 @@ void Slvs_MakeQuaternion(double ux, double uy, double uz, void Slvs_Solve(Slvs_System *ssys, Slvs_hGroup shg) { if(!IsInit) { - InitHeaps(); + InitPlatform(); IsInit = 1; } diff --git a/src/platform/cocoamain.mm b/src/platform/cocoamain.mm index 9b87514c..7c17401b 100644 --- a/src/platform/cocoamain.mm +++ b/src/platform/cocoamain.mm @@ -7,11 +7,7 @@ //----------------------------------------------------------------------------- #include #include - -#import - -#include -#include +#import #include "solvespace.h" @@ -1138,26 +1134,6 @@ std::vector SolveSpace::GetFontFiles() { return fonts; } -const void *SolveSpace::LoadResource(const std::string &name, size_t *size) { - static NSMutableDictionary *cache; - - if(cache == nil) { - cache = [[NSMutableDictionary alloc] init]; - } - - NSString *key = [NSString stringWithUTF8String:name.c_str()]; - NSData *data = [cache objectForKey:key]; - if(data == nil) { - NSString *path = [[NSBundle mainBundle] pathForResource:key ofType:nil]; - data = [[NSFileHandle fileHandleForReadingAtPath:path] readDataToEndOfFile]; - ssassert(data != nil, "Cannot find resource"); - [cache setObject:data forKey:key]; - } - - *size = [data length]; - return [data bytes]; -} - /* Application lifecycle */ @interface ApplicationDelegate : NSObject diff --git a/src/platform/gtkmain.cpp b/src/platform/gtkmain.cpp index 60e210ac..473030b4 100644 --- a/src/platform/gtkmain.cpp +++ b/src/platform/gtkmain.cpp @@ -1482,73 +1482,6 @@ std::vector GetFontFiles() { return fonts; } -std::string ExpandPath(std::string path) { - char *expanded_c_path = realpath(path.c_str(), NULL); - if(expanded_c_path == NULL) { - fprintf(stderr, "realpath(%s): %s\n", path.c_str(), strerror(errno)); - return ""; - } - std::string expanded_path = expanded_c_path; - free(expanded_c_path); - return expanded_path; -} - -static std::string resource_dir; -void FindLocalResourceDir(const char *argv0) { - // Getting path to your own executable is a total portability disaster. - // Good job *nix OSes; you're basically all awful here. - std::string self_path; -#if defined(__linux__) - self_path = "/proc/self/exe"; -#elif defined(__NetBSD__) - self_path = "/proc/curproc/exe" -#elif defined(__OpenBSD__) - self_path = "/proc/curproc/file"; -#else - self_path = argv0; -#endif - - resource_dir = ExpandPath(self_path); - if(resource_dir.empty()) { - fprintf(stderr, "Cannot determine path to executable; using global resources.\n"); - return; - } - resource_dir.erase(resource_dir.rfind('/')); - resource_dir += "/../res"; - resource_dir = ExpandPath(resource_dir); -} - -const void *LoadResource(const std::string &name, size_t *size) { - static std::map> cache; - - auto it = cache.find(name); - if(it == cache.end()) { - struct stat st; - std::string path; - - if(resource_dir.empty()) { - path = (UNIX_DATADIR "/") + name; - } else { - path = resource_dir + "/" + name; - } - - if(stat(path.c_str(), &st)) { - ssassert(!stat(path.c_str(), &st), "Cannot find resource"); - } - - std::vector data(st.st_size); - FILE *f = ssfopen(path.c_str(), "rb"); - ssassert(f != NULL, "Cannot open resource"); - fread(&data[0], 1, st.st_size, f); - fclose(f); - - cache.emplace(name, std::move(data)); - it = cache.find(name); - } - - *size = (*it).second.size(); - return &(*it).second[0]; -} /* Space Navigator support */ @@ -1612,9 +1545,6 @@ int main(int argc, char** argv) { ambiguous. */ gtk_disable_setlocale(); - /* If we're running from the build directory, grab the local resources. */ - FindLocalResourceDir(argv[0]); - Gtk::Main main(argc, argv); #ifdef HAVE_SPACEWARE diff --git a/src/platform/headless.cpp b/src/platform/headless.cpp index 7eefa5dc..9be35d08 100644 --- a/src/platform/headless.cpp +++ b/src/platform/headless.cpp @@ -251,31 +251,6 @@ std::vector GetFontFiles() { return fontFiles; } -std::string resourceDir; -const void *LoadResource(const std::string &name, size_t *size) { - static std::map> cache; - - auto it = cache.find(name); - if(it == cache.end()) { - std::string path = resourceDir + "/" + name; - std::vector data; - - FILE *f = ssfopen(PathSepUnixToPlatform(path).c_str(), "rb"); - ssassert(f != NULL, "Cannot open resource"); - fseek(f, 0, SEEK_END); - data.resize(ftell(f)); - fseek(f, 0, SEEK_SET); - fread(&data[0], 1, data.size(), f); - fclose(f); - - cache.emplace(name, std::move(data)); - it = cache.find(name); - } - - *size = (*it).second.size(); - return &(*it).second[0]; -} - //----------------------------------------------------------------------------- // Application lifecycle //----------------------------------------------------------------------------- diff --git a/src/platform/unixutil.cpp b/src/platform/unixutil.cpp index f076cc99..9594bf07 100644 --- a/src/platform/unixutil.cpp +++ b/src/platform/unixutil.cpp @@ -7,13 +7,18 @@ // Copyright 2008-2013 Jonathan Westhues. // Copyright 2013 Daniel Richard G. //----------------------------------------------------------------------------- -#include +#include +#include #include #ifdef __APPLE__ # include // for strcasecmp +# include +# include +# include #endif #include "solvespace.h" +#include "config.h" namespace SolveSpace { @@ -89,6 +94,104 @@ void ssremove(const std::string &filename) remove(filename.c_str()); } +static std::string ExpandPath(std::string path) { + char *expanded_c_path = realpath(path.c_str(), NULL); + if(expanded_c_path == NULL) { + fprintf(stderr, "realpath(%s): %s\n", path.c_str(), strerror(errno)); + return ""; + } + std::string expanded_path = expanded_c_path; + free(expanded_c_path); + return expanded_path; +} + +static const std::string &FindLocalResourceDir() { + static std::string resourceDir; + static bool checked; + + if(checked) return resourceDir; + checked = true; + + // Getting path to your own executable is a total portability disaster. + // Good job *nix OSes; you're basically all awful here. + std::string selfPath; +#if defined(__linux__) + selfPath = "/proc/self/exe"; +#elif defined(__NetBSD__) + selfPath = "/proc/curproc/exe" +#elif defined(__OpenBSD__) + selfPath = "/proc/curproc/file"; +#elif defined(__APPLE__) + CFURLRef cfUrl = + CFBundleCopyExecutableURL(CFBundleGetMainBundle()); + CFStringRef cfPath = CFURLCopyFileSystemPath(cfUrl, kCFURLPOSIXPathStyle); + selfPath.resize(CFStringGetLength(cfPath) + 1); // reserve space for NUL + ssassert(CFStringGetCString(cfPath, &selfPath[0], selfPath.size(), kCFStringEncodingUTF8), + "Cannot convert CFString to C string"); + selfPath.resize(selfPath.size() - 1); + CFRelease(cfUrl); + CFRelease(cfPath); +#else + // We don't know how to find the local resource directory on this platform, + // so use the global one (by returning an empty string). + return resourceDir; +#endif + + resourceDir = ExpandPath(selfPath); + if(!resourceDir.empty()) { + resourceDir.erase(resourceDir.rfind('/')); + resourceDir += "/../res"; + resourceDir = ExpandPath(resourceDir); + } + if(!resourceDir.empty()) { + struct stat st; + if(stat(resourceDir.c_str(), &st)) { + // We looked at the path where the local resource directory ought to be, + // but there isn't one, so use the global one. + resourceDir = ""; + } + } + return resourceDir; +} + +const void *LoadResource(const std::string &name, size_t *size) { + static std::map cache; + + auto it = cache.find(name); + if(it == cache.end()) { + const std::string &resourceDir = FindLocalResourceDir(); + + std::string path; + if(resourceDir.empty()) { +#if defined(__APPLE__) + CFStringRef cfName = + CFStringCreateWithCString(kCFAllocatorDefault, name.c_str(), + kCFStringEncodingUTF8); + CFURLRef cfUrl = + CFBundleCopyResourceURL(CFBundleGetMainBundle(), cfName, NULL, NULL); + CFStringRef cfPath = CFURLCopyFileSystemPath(cfUrl, kCFURLPOSIXPathStyle); + path.resize(CFStringGetLength(cfPath) + 1); // reserve space for NUL + ssassert(CFStringGetCString(cfPath, &path[0], path.size(), kCFStringEncodingUTF8), + "Cannot convert CFString to C string"); + path.resize(path.size() - 1); + CFRelease(cfName); + CFRelease(cfUrl); + CFRelease(cfPath); +#else + path = (UNIX_DATADIR "/") + name; +#endif + } else { + path = resourceDir + "/" + name; + } + + ssassert(ReadFile(path, &cache[name]), "Cannot read resource"); + it = cache.find(name); + } + + *size = (*it).second.size(); + return static_cast(&(*it).second[0]); +} + //----------------------------------------------------------------------------- // A separate heap, on which we allocate expressions. Maybe a bit faster, // since fragmentation is less of a concern, and it also makes it possible @@ -150,7 +253,7 @@ void MemFree(void *p) { free(p); } -void InitHeaps(void) { +void InitPlatform(void) { /* nothing to do */ } diff --git a/src/platform/w32main.cpp b/src/platform/w32main.cpp index d0837bed..7ba6d2a7 100644 --- a/src/platform/w32main.cpp +++ b/src/platform/w32main.cpp @@ -1397,16 +1397,6 @@ static void CreateMainWindows() ClientIsSmallerBy = (r.bottom - r.top) - (rc.bottom - rc.top); } -const void *SolveSpace::LoadResource(const std::string &name, size_t *size) { - HRSRC hres = FindResourceW(NULL, Widen(name).c_str(), RT_RCDATA); - ssassert(hres != NULL, "Cannot find resource"); - HGLOBAL res = LoadResource(NULL, hres); - ssassert(res != NULL, "Cannot load resource"); - - *size = SizeofResource(NULL, hres); - return LockResource(res); -} - #ifdef HAVE_SPACEWARE //----------------------------------------------------------------------------- // Test if a message comes from the SpaceNavigator device. If yes, dispatch @@ -1474,7 +1464,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, ShowWindow(GraphicsWnd, SW_SHOW); // Create the heaps for all dynamic memory (AllocTemporary, MemAlloc) - InitHeaps(); + InitPlatform(); // Pull out the Unicode command line. int argc; diff --git a/src/platform/w32util.cpp b/src/platform/w32util.cpp index 29357e5d..99ad1237 100644 --- a/src/platform/w32util.cpp +++ b/src/platform/w32util.cpp @@ -144,6 +144,16 @@ void ssremove(const std::string &filename) _wremove(Widen(filename).c_str()); } +const void *LoadResource(const std::string &name, size_t *size) { + HRSRC hres = FindResourceW(NULL, Widen(name).c_str(), RT_RCDATA); + ssassert(hres != NULL, "Cannot find resource"); + HGLOBAL res = ::LoadResource(NULL, hres); + ssassert(res != NULL, "Cannot load resource"); + + *size = SizeofResource(NULL, hres); + return LockResource(res); +} + //----------------------------------------------------------------------------- // A separate heap, on which we allocate expressions. Maybe a bit faster, // since no fragmentation issues whatsoever, and it also makes it possible @@ -182,10 +192,17 @@ void vl() { ssassert(HeapValidate(PermHeap, HEAP_NO_SERIALIZE, NULL), "Corrupted heap"); } -void InitHeaps() { +void InitPlatform() { // Create the heap used for long-lived stuff (that gets freed piecewise). PermHeap = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0); // Create the heap that we use to store Exprs and other temp stuff. FreeAllTemporary(); + +#if !defined(LIBRARY) && defined(_MSC_VER) + // Don't display the abort message; it is aggravating in CLI binaries + // and results in infinite WndProc recursion in GUI binaries. + _set_abort_behavior(0, _WRITE_ABORT_MSG); +#endif } + } diff --git a/src/solvespace.h b/src/solvespace.h index faa9bd80..17ae3e01 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -294,7 +294,7 @@ void FreeTemporary(void *p); void FreeAllTemporary(); void *MemAlloc(size_t n); void MemFree(void *p); -void InitHeaps(); +void InitPlatform(); void vl(); // debug function to validate heaps #include "resource.h" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 081477ad..fa18451e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -58,12 +58,16 @@ set(testsuite_SOURCES ) add_executable(solvespace_testsuite - ${testsuite_SOURCES}) + ${testsuite_SOURCES} + $) target_link_libraries(solvespace_testsuite solvespace_headless ${COVERAGE_LIBRARY}) +add_dependencies(solvespace_testsuite + resources) + add_custom_target(solvespace-test ALL COMMAND $ COMMENT "Testing SolveSpace" diff --git a/test/harness.cpp b/test/harness.cpp index 431a446a..6cfa9967 100644 --- a/test/harness.cpp +++ b/test/harness.cpp @@ -3,18 +3,19 @@ // // Copyright 2016 whitequark //----------------------------------------------------------------------------- -#include "harness.h" #include #include + +#include "harness.h" + #if defined(WIN32) -#include +# include #else -#include +# include #endif namespace SolveSpace { // These are defined in headless.cpp, and aren't exposed in solvespace.h. - extern std::string resourceDir; extern std::vector fontFiles; extern bool antialias; extern std::shared_ptr framebuffer; @@ -291,12 +292,7 @@ int Test::Case::Register(Test::Case testCase) { } int main(int argc, char **argv) { -#if defined(_MSC_VER) - _set_abort_behavior(0, _WRITE_ABORT_MSG); -#endif -#if defined(WIN32) - InitHeaps(); -#endif + InitPlatform(); std::regex filter(".*"); if(argc == 1) { @@ -307,10 +303,6 @@ int main(int argc, char **argv) { return 1; } - resourceDir = HostRoot(); - resourceDir.erase(resourceDir.rfind(HOST_PATH_SEP) + 1); - resourceDir += "res"; - fontFiles.push_back(HostRoot() + HOST_PATH_SEP + "Gentium-R.ttf"); // Different Cairo versions have different antialiasing algorithms.