diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 93beaa6355..4334743bb2 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,16 +1,22 @@ set(APP_SOURCES exiv2.cpp - exiv2app.hpp actions.cpp - actions.hpp getopt.cpp - getopt.hpp app_utils.cpp - app_utils.hpp ) add_executable(exiv2 ${APP_SOURCES}) +# Make app use UTF-8 code page in Windows +if(WIN32) + if(MSVC) + target_sources(exiv2 PRIVATE utf8.manifest) + else() + # Must wrap manifest in .rc w/ other toolchains + target_sources(exiv2 PRIVATE utf8.rc) + endif() +endif() + target_include_directories(exiv2 PRIVATE ${PROJECT_SOURCE_DIR}/src) # To find i18n.hpp set_target_properties(exiv2 PROPERTIES COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS} XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES") @@ -27,24 +33,6 @@ endif() target_link_libraries(exiv2 PRIVATE std::filesystem) -if(MSVC OR MINGW) - # Trick to get properly UTF-8 encoded argv. - - # More info at: https://github.com/huangqinjin/wmain - add_library(wmain STATIC wmain.cpp) - target_link_libraries(exiv2 PRIVATE wmain) -endif() - -if(MSVC) - target_link_options(wmain INTERFACE /WHOLEARCHIVE:$) - target_link_options(exiv2 PRIVATE "/ENTRY:wWinMainCRTStartup") -endif() - -if(MINGW) - target_compile_options(exiv2 PRIVATE -municode) - target_link_options(exiv2 PRIVATE -municode) -endif() - if(USING_CONAN AND WIN32 AND EXISTS ${PROJECT_BINARY_DIR}/conanDlls diff --git a/app/exiv2.cpp b/app/exiv2.cpp index b74a4da83a..14c8f6c0d3 100644 --- a/app/exiv2.cpp +++ b/app/exiv2.cpp @@ -114,8 +114,6 @@ std::string parseEscapes(const std::string& input); // ***************************************************************************** // Main int main(int argc, char* const argv[]) { - setlocale(LC_CTYPE, ".utf8"); - Exiv2::XmpParser::initialize(); ::atexit(Exiv2::XmpParser::terminate); diff --git a/app/utf8.manifest b/app/utf8.manifest new file mode 100644 index 0000000000..f205604931 --- /dev/null +++ b/app/utf8.manifest @@ -0,0 +1,8 @@ + + + + + UTF-8 + + + \ No newline at end of file diff --git a/app/utf8.rc b/app/utf8.rc new file mode 100644 index 0000000000..b4cca2abbe --- /dev/null +++ b/app/utf8.rc @@ -0,0 +1,3 @@ +#include + +CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "utf8.manifest" diff --git a/app/wmain.cpp b/app/wmain.cpp deleted file mode 100644 index a1fcfaf99b..0000000000 --- a/app/wmain.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -#include - -extern int __cdecl main(int, char*[]); - -int wmain(int argc, wchar_t* argv[]) { - char** args; - int nbytes = static_cast(sizeof(char*) * (argc + 1)); - HANDLE heap = GetProcessHeap(); - - for (int i = 0; i < argc; ++i) - nbytes += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr); - - args = reinterpret_cast(HeapAlloc(heap, 0, nbytes)); - args[0] = reinterpret_cast(args + argc + 1); - - for (int i = 0; i < argc; ++i) - args[i + 1] = args[i] + WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, args[i], nbytes, nullptr, nullptr); - - args[argc] = nullptr; - - argc = main(argc, args); - HeapFree(heap, 0, args); - return argc; -} - -int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { - (void)hInstance; - (void)hPrevInstance; - (void)lpCmdLine; - (void)nCmdShow; - - int argc; - wchar_t** argv; - argv = CommandLineToArgvW(GetCommandLineW(), &argc); - argc = wmain(argc, argv); - LocalFree(argv); - return argc; -} diff --git a/cmake/mainSetup.cmake b/cmake/mainSetup.cmake index 1ea9debec4..6f8e60faee 100644 --- a/cmake/mainSetup.cmake +++ b/cmake/mainSetup.cmake @@ -3,6 +3,7 @@ include(GNUInstallDirs) include(CheckFunctionExists) +include(CheckCXXSymbolExists) include(GenerateExportHeader) include(CMakeDependentOption) include(cmake/JoinPaths.cmake) @@ -31,6 +32,13 @@ if (UNIX) endif() endif() +if(MINGW) + check_cxx_symbol_exists(_UCRT "ctime" USES_UCRT) + if(NOT USES_UCRT) + message(FATAL_ERROR "Non UCRT MinGW is unsupported. Please update toolchain") + endif() +endif() + # Prevent conflicts when exiv2 is consumed in multiple-subdirectory projects. if (NOT TARGET uninstall) configure_file(cmake/exiv2_uninstall.cmake ${CMAKE_BINARY_DIR}/cmake_uninstall.cmake COPYONLY) diff --git a/meson.build b/meson.build index 2534afc488..faceff630c 100644 --- a/meson.build +++ b/meson.build @@ -142,9 +142,13 @@ exiv2_sources = files( 'app/app_utils.cpp', 'app/exiv2.cpp', 'app/getopt.cpp', - host_machine.system() == 'windows' ? 'app/wmain.cpp' : [], ) +if host_machine.system() == 'windows' + windows = import('windows') + exiv2_sources += windows.compile_resources('app/utf8.rc', depend_files: 'app/utf8.manifest') +endif + exiv2inc = include_directories('src', 'include/exiv2') executable( 'exiv2', diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index d2a17ca550..843f763daa 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -107,16 +107,16 @@ list(APPEND APPLICATIONS remotetest) # ****************************************************************************** foreach(application ${APPLICATIONS}) - target_link_libraries(${application} PRIVATE exiv2lib std::filesystem) - if(MSVC) - target_link_libraries(${application} PRIVATE wmain) - target_link_options(${application} PRIVATE "/ENTRY:wWinMainCRTStartup") - endif() - if(MINGW) - target_link_libraries(${application} PRIVATE wmain) - target_compile_options(${application} PRIVATE -municode) - target_link_options(${application} PRIVATE -municode) + # Make app use UTF-8 code page in Windows + if(WIN32) + if(MSVC) + target_sources(${application} PRIVATE ${PROJECT_SOURCE_DIR}/app/utf8.manifest) + else() + # Must wrap manifest in .rc w/ other toolchains + target_sources(${application} PRIVATE ${PROJECT_SOURCE_DIR}/app/utf8.rc) + endif() endif() + target_link_libraries(${application} PRIVATE exiv2lib std::filesystem) if(EXIV2_ENABLE_PNG) target_link_libraries(${application} PRIVATE ${ZLIB_LIBRARIES}) if(MSVC) diff --git a/samples/exifprint.cpp b/samples/exifprint.cpp index f528fafa61..cdefeb947f 100644 --- a/samples/exifprint.cpp +++ b/samples/exifprint.cpp @@ -13,7 +13,6 @@ static const Exiv2::TagInfo* findTag(const Exiv2::TagInfo* pList, uint16_t tag) int main(int argc, char* const argv[]) { try { - setlocale(LC_CTYPE, ".utf8"); Exiv2::XmpParser::initialize(); ::atexit(Exiv2::XmpParser::terminate);