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 c858d4c..970e403 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 40fffc5..fa8a96e 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 8d83994..5533b17 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 9531820..18e5736 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 bdae469..cb2367c 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 c87a492..216b427 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 7880c3b..91cfe79 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 8a4bdf0..d9abe3c 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 9b87514..7c17401 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 60e210a..473030b 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 7eefa5d..9be35d0 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 f076cc9..9594bf0 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 d0837be..7ba6d2a 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 29357e5..99ad123 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 faa9bd8..17ae3e0 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 081477a..fa18451 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 431a446..6cfa996 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.