From d00bd20fea5c6304b42ee3e9ac3cb6f20885f4bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Valverde?= Date: Wed, 11 Jan 2023 00:10:05 +0000 Subject: [PATCH] MSYS2: Fix system installation Make the "ninja install" target in the MINGW64 shell work and allow Wireshark to run from the msys2 installation, besides the build directory. To clarify the names used here MSYSTEM is the distribution with a Linux-like environment for Windows. MINGW is the toolchain. It is possible to use MinGW without MSYS2 and we generally select the CMake variables WIN32/MSVC/MINGW/USE_MSYSTEM taking that into consideration but that WIN32+MINGW platform is not supported at the moment and it's unlikely to be supported in the near future. --- CMakeLists.txt | 79 ++++++++++++++--------------- ui/qt/main.cpp | 7 ++- wsutil/CMakeLists.txt | 21 ++++++-- wsutil/filesystem.c | 113 ++++++++++++++++++++++++++++++++++-------- 4 files changed, 152 insertions(+), 68 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2526ed5656..af1b52a054 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,20 @@ if(POLICY CMP0083) endif() if(WIN32) + if(DEFINED ENV{MSYSTEM}) + set(_msystem $ENV{MSYSTEM}) + set(_repository False) + message(STATUS "Using MSYS2 with MSYSTEM=${_msystem}") + else() + set(_msystem False) + set(_repository True) + message(STATUS "Using 3rd party repository") + endif() + set(USE_MSYSTEM ${_msystem} CACHE INTERNAL "Use MSYS2 subsystem") + set(USE_REPOSITORY ${_repository} CACHE INTERNAL "Use Wireshark 3rd Party Repository") +endif() + +if(WIN32 AND NOT USE_MSYSTEM) set(_project_name Wireshark) set(_log_project_name Logray) else() @@ -101,27 +115,11 @@ endif() # %WIRESHARK_TARGET_PLATFORM%. if(WIN32) - # Are we using MSYS2? If we are we don't use our own third party - # libraries. - if(DEFINED ENV{MSYSTEM}) - set(_msystem $ENV{MSYSTEM}) - set(_repository False) - message(STATUS "Using MSYS2 with MSYSTEM=${_msystem}") - else() - set(_msystem False) - set(_repository True) - message(STATUS "Using 3rd party repository") - endif() - set(USE_MSYSTEM ${_msystem} CACHE INTERNAL "Use MSYS2 subsystem") - set(USE_REPOSITORY ${_repository} CACHE INTERNAL "Use Wireshark 3rd Party Repository") - if(DEFINED ENV{WIRESHARK_TARGET_PLATFORM}) string(TOLOWER $ENV{WIRESHARK_TARGET_PLATFORM} _target_platform) set(WIRESHARK_TARGET_PLATFORM ${_target_platform}) elseif(USE_MSYSTEM MATCHES "MINGW64") set(WIRESHARK_TARGET_PLATFORM win64) - elseif(USE_MSYSTEM MATCHES "MINGW32") - set(WIRESHARK_TARGET_PLATFORM win32) elseif(USE_MSYSTEM) message(WARNING "Building for MSYSTEM=${USE_MSYSTEM} is not officially supported") elseif(CMAKE_CL_64 OR CMAKE_GENERATOR MATCHES "Win64") @@ -226,7 +224,7 @@ endif() # # Defines CMAKE_INSTALL_BINDIR, CMAKE_INSTALL_DATADIR, etc ... -if(WIN32) +if(WIN32 AND NOT USE_MSYSTEM) # Override some values on Windows, to match the existing # convention of installing everything to a single root folder. set(CMAKE_INSTALL_BINDIR ".") @@ -315,7 +313,7 @@ include(CheckSymbolExists) # Studio has had supported them since Visual Studio 2005/MSVCR80, # and we require newer versions, so we know we have them. # -if(NOT WIN32) +if(NOT MSVC) include(FindLFS) if(LFS_FOUND) # @@ -1166,7 +1164,7 @@ if(BUILD_wireshark OR BUILD_logray) if(DEFINED ENV{WIRESHARK_QT5_PREFIX_PATH}) list(APPEND CMAKE_PREFIX_PATH $ENV{WIRESHARK_QT5_PREFIX_PATH}) # XXX We used to recommend setting QT5_BASE_DIR. Remove after the 4.0 branch is created. - elseif(WIN32 AND DEFINED ENV{QT5_BASE_DIR}) + elseif(WIN32 AND NOT USE_MSYSTEM AND DEFINED ENV{QT5_BASE_DIR}) message(WARNING "Support for QT5_BASE_DIR will be removed in a future release.") set(QT5_BASE_PATH "$ENV{QT5_BASE_DIR}") set(CMAKE_PREFIX_PATH "${QT5_BASE_PATH}") @@ -1342,7 +1340,7 @@ if(GNUTLS_FOUND) # Check that the support is present in case GnuTLS was compiled # --without-p11-kit as macos-setup.sh did until December 2020. cmake_push_check_state() - if(WIN32) + if(WIN32 AND NOT MINGW) set(CMAKE_REQUIRED_DEFINITIONS -Dssize_t=int) endif() set(CMAKE_REQUIRED_INCLUDES ${GNUTLS_INCLUDE_DIRS}) @@ -1374,13 +1372,8 @@ if (QT_FOUND) ) # Use qmake to find windeployqt and macdeployqt. Ideally one of # the modules in ${QTDIR}/lib/cmake would do this for us. - if(WIN32) - if (USE_qt6 AND USE_MSYSTEM) - set(_windeployqt_name "windeployqt-qt6") - else() - set(_windeployqt_name "windeployqt") - endif() - find_program(QT_WINDEPLOYQT_EXECUTABLE ${_windeployqt_name} + if(WIN32 AND NOT USE_MSYSTEM) + find_program(QT_WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${QT_BIN_PATH}" DOC "Path to the windeployqt utility." ) @@ -1483,11 +1476,12 @@ include( UseCheckAPI ) # macOS app bundle: Wireshark.app/Contents/Resources/share/wireshark/extcap # If you change the nesting level be sure to check also the INSTALL_RPATH # target property. -if (WIN32) +if(WIN32 AND NOT USE_MSYSTEM) set(EXTCAP_INSTALL_LIBDIR "extcap" CACHE INTERNAL "The extcap dir") -else () +else() set(EXTCAP_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/extcap" CACHE INTERNAL "The extcap dir") endif() +set(EXTCAP_INSTALL_FULL_LIBDIR "${CMAKE_INSTALL_PREFIX}/${EXTCAP_INSTALL_LIBDIR}") if(APPLE) # @@ -1508,11 +1502,12 @@ else() endif() # Directory where plugins and Lua dissectors can be found. -if(WIN32) +if(WIN32 AND NOT USE_MSYSTEM) set(PLUGIN_INSTALL_LIBDIR "plugins" CACHE INTERNAL "The plugin dir") else() set(PLUGIN_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/plugins" CACHE INTERNAL "The plugin dir") endif() +set(PLUGIN_INSTALL_FULL_LIBDIR "${CMAKE_INSTALL_PREFIX}/${PLUGIN_INSTALL_LIBDIR}") set(PLUGIN_INSTALL_VERSION_LIBDIR "${PLUGIN_INSTALL_LIBDIR}/${PLUGIN_PATH_ID}") set(PLUGIN_VERSION_DIR "plugins/${PLUGIN_PATH_ID}") @@ -1668,7 +1663,7 @@ if(ENABLE_APPLICATION_BUNDLE) # Xcode set(_logray_plugin_dir "${CMAKE_BINARY_DIR}/run/$/Logray.app/Contents/PlugIns/logray/${PLUGIN_PATH_ID}") endif() -elseif(WIN32 AND NOT CMAKE_CFG_INTDIR STREQUAL ".") +elseif(MSVC AND NOT CMAKE_CFG_INTDIR STREQUAL ".") set(_plugin_dir "${CMAKE_BINARY_DIR}/run/$/${PLUGIN_VERSION_DIR}") set(_logray_plugin_dir ${_plugin_dir}) else() @@ -2215,7 +2210,7 @@ endif() # List of extra dependencies for the "copy_data_files" target set(copy_data_files_depends) -if(WIN32) +if(WIN32 AND NOT USE_MSYSTEM) foreach(_install_as_txt_file COPYING NEWS README.md README.windows) # On Windows, install some files with a .txt extension so that they're # double-clickable. @@ -2610,7 +2605,7 @@ if(BUILD_wireshark AND QT_FOUND) ) add_executable(wireshark WIN32 MACOSX_BUNDLE ${wireshark_FILES} ${EXTRA_WIRESHARK_BUNDLE_FILES}) - if(WIN32) + if(MSVC) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT wireshark) endif() set(PROGLIST ${PROGLIST} wireshark) @@ -2625,7 +2620,9 @@ if(BUILD_wireshark AND QT_FOUND) if(MSVC) set_target_properties(wireshark PROPERTIES LINK_FLAGS_DEBUG "${WS_MSVC_DEBUG_LINK_FLAGS}") endif() - if(ENABLE_APPLICATION_BUNDLE OR WIN32) + if (USE_MSYSTEM) + set_target_properties(wireshark PROPERTIES OUTPUT_NAME wireshark) + elseif(ENABLE_APPLICATION_BUNDLE OR WIN32) set_target_properties(wireshark PROPERTIES OUTPUT_NAME Wireshark) endif() @@ -3210,7 +3207,7 @@ if(BUILD_dcerpcidl2wrs) install(TARGETS idl2wrs RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() -if (WIN32) +if(MSVC) find_package( MSVC_REDIST ) # Must come after executable targets are defined. @@ -3728,7 +3725,7 @@ if(CLEAN_C_FILES) # the INCLUDE environment variable). # This should apparently be handled for us via CMAKE_RC_FLAG_REGEX # in CMakeRCInformation.cmake but that doesn't appear to work. - if(WIN32) + if(MSVC) list(FILTER CLEAN_C_FILES EXCLUDE REGEX ".*\\.rc") endif() @@ -3771,7 +3768,7 @@ install(FILES ${SHARK_PUBLIC_HEADERS} ) # Install icons and other desktop files for Freedesktop.org-compliant desktops. -if((BUILD_wireshark AND QT_FOUND) AND NOT (WIN32 OR APPLE)) +if(BUILD_wireshark AND QT_FOUND AND NOT APPLE AND (NOT WIN32 OR USE_MSYSTEM)) install(FILES resources/freedesktop/org.wireshark.Wireshark-mime.xml DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/mime/packages" RENAME org.wireshark.Wireshark.xml @@ -3821,7 +3818,7 @@ install( PATTERN "Makefile.*" EXCLUDE ) -if(WIN32) +if(WIN32 AND NOT USE_MSYSTEM) # Note: CMake export mechanism misbehaves with a '.' in the # path (incorrect relative path computation). set(WIRESHARK_INSTALL_CMAKEDIR "cmake") @@ -3880,7 +3877,7 @@ if (DOXYGEN_EXECUTABLE) COMMAND ${DOXYGEN_EXECUTABLE} doxygen.cfg ) - if (WIN32) + if(WIN32 AND NOT USE_MSYSTEM) add_custom_target(wsar_html_perms DEPENDS wsar_html) else() add_custom_target(wsar_html_perms @@ -4012,7 +4009,7 @@ else (GIT_EXECUTABLE) endif (GIT_EXECUTABLE) set_target_properties(gen-authors PROPERTIES FOLDER "Documentation") -if (WIN32) +if(WIN32 AND NOT USE_MSYSTEM) file (TO_NATIVE_PATH ${CMAKE_SOURCE_DIR}/tools/Get-HardenFlags.ps1 _win_harden_flags) add_custom_target(hardening-check COMMAND ${POWERSHELL_COMMAND} "${_win_harden_flags}" "${_dll_output_dir_win}" @@ -4020,7 +4017,7 @@ if (WIN32) COMMENT "Checking binaries for security features" ) set_target_properties(hardening-check PROPERTIES FOLDER "Tests") -else () +else() find_program(HARDENING_CHECK_EXECUTABLE hardening-check DOC "Path to the hardening-check utility." ) diff --git a/ui/qt/main.cpp b/ui/qt/main.cpp index 68b53ffa7e..aba9f051c5 100644 --- a/ui/qt/main.cpp +++ b/ui/qt/main.cpp @@ -342,7 +342,7 @@ check_and_warn_user_startup() } #endif -#ifdef _WIN32 +#if defined(_WIN32) && !defined(__MINGW64__) // Try to avoid library search path collisions. QCoreApplication will // search QT_INSTALL_PREFIX/plugins for platform DLLs before searching // the application directory. If @@ -360,6 +360,9 @@ check_and_warn_user_startup() // same path on the build machine. At any rate, loading DLLs from paths // you don't control is ill-advised. We work around this by removing every // path except our application directory. +// +// NOTE: This does not apply to MinGW-w64 using MSYS2. In that case we use +// the system's Qt plugins with the default search paths. static inline void win32_reset_library_path(void) @@ -647,7 +650,7 @@ int main(int argc, char *qt_argv[]) commandline_early_options(argc, argv); -#ifdef _WIN32 +#if defined(_WIN32) && !defined(__MINGW64__) win32_reset_library_path(); #endif diff --git a/wsutil/CMakeLists.txt b/wsutil/CMakeLists.txt index 61786a1ccb..420ae5c179 100644 --- a/wsutil/CMakeLists.txt +++ b/wsutil/CMakeLists.txt @@ -7,9 +7,24 @@ # SPDX-License-Identifier: GPL-2.0-or-later # -add_definitions(-DPLUGIN_DIR=\"${CMAKE_INSTALL_PREFIX}/${PLUGIN_INSTALL_LIBDIR}\") -add_definitions(-DEXTCAP_DIR=\"${CMAKE_INSTALL_PREFIX}/${EXTCAP_INSTALL_LIBDIR}\") -add_definitions(-DDATA_DIR=\"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}\") +if(UNIX OR USE_MSYSTEM) + if(USE_MSYSTEM) + # Windows binaries are relocatable and do not need a prefix. + file(TO_NATIVE_PATH "${PLUGIN_INSTALL_LIBDIR}" _dir) + string(REPLACE "\\" "\\\\" _plugin_dir "${_dir}") + file(TO_NATIVE_PATH "${EXTCAP_INSTALL_LIBDIR}" _dir) + string(REPLACE "\\" "\\\\" _extcap_dir "${_dir}") + file(TO_NATIVE_PATH "${CMAKE_INSTALL_DATADIR}" _dir) + string(REPLACE "\\" "\\\\" _data_dir "${_dir}") + elseif(UNIX) + set(_plugin_dir "${PLUGIN_INSTALL_FULL_LIBDIR}") + set(_extcap_dir "${EXTCAP_INSTALL_FULL_LIBDIR}") + set(_data_dir "${CMAKE_INSTALL_FULL_DATADIR}") + endif() + add_definitions(-DPLUGIN_DIR=\"${_plugin_dir}\") + add_definitions(-DEXTCAP_DIR=\"${_extcap_dir}\") + add_definitions(-DDATA_DIR=\"${_data_dir}\") +endif() add_subdirectory(wmem) diff --git a/wsutil/filesystem.c b/wsutil/filesystem.c index 27813ffdc3..32113624ed 100644 --- a/wsutil/filesystem.c +++ b/wsutil/filesystem.c @@ -51,6 +51,8 @@ #define PLUGINS_DIR_NAME "plugins" #define PROFILES_INFO_NAME "profile_files.txt" +#define _S G_DIR_SEPARATOR_S + /* * Application configuration namespace. Used to construct configuration * paths and environment variables. @@ -73,6 +75,12 @@ char *datafile_dir = NULL; char *persdatafile_dir = NULL; char *persconfprofile = NULL; +/* Directory from which the executable came. */ +static char *progfile_dir = NULL; +#ifdef __MINGW64__ +static char *install_prefix = NULL; +#endif + static gboolean do_store_persconffiles = FALSE; static GHashTable *profile_files = NULL; @@ -209,11 +217,6 @@ test_for_fifo(const char *path) return 0; } -/* - * Directory from which the executable came. - */ -static char *progfile_dir; - #ifdef __APPLE__ /* * Directory of the application bundle in which we're contained, @@ -531,6 +534,19 @@ static void trim_progfile_dir(void) g_free(extcap_progfile_dir); } +#ifdef __MINGW64__ +static char * +trim_last_dir_from_path(const char *_path) +{ + char *path = ws_strdup(_path); + char *last_dir = find_last_pathname_separator(path); + if (last_dir) { + *last_dir = '\0'; + } + return path; +} +#endif + /* * Construct the path name of a non-extcap Wireshark executable file, * given the program name. The executable name doesn't include ".exe"; @@ -562,19 +578,10 @@ get_executable_path(const char *program_name) * and save it for future use. Returns NULL on success, and a * g_mallocated string containing an error on failure. */ +#ifdef _WIN32 char * -configuration_init( -#ifdef _WIN32 - const char* arg0 _U_, -#else - const char* arg0, -#endif - const char *namespace_name -) +configuration_init_w32(const char* arg0 _U_) { - set_configuration_namespace(namespace_name); - -#ifdef _WIN32 TCHAR prog_pathname_w[_MAX_PATH+2]; char *prog_pathname; DWORD error; @@ -599,7 +606,7 @@ configuration_init( progfile_dir = g_path_get_dirname(prog_pathname); if (progfile_dir != NULL) { trim_progfile_dir(); - return NULL; /* we succeeded */ + /* we succeeded */ } else { /* * OK, no. What do we do now? @@ -634,7 +641,32 @@ configuration_init( return ws_strdup_printf("GetModuleFileName failed: %s (%u)", msg, error); } -#else + +#ifdef __MINGW64__ + /* + * We already have the program_dir. Find the installation prefix. + * This is one level up from the bin_dir. If the program_dir does + * not end with "bin" then assume we are running in the build directory + * and the "installation prefix" (staging directory) is the same as + * the program_dir. + */ + if (g_str_has_suffix(progfile_dir, _S"bin")) { + install_prefix = trim_last_dir_from_path(progfile_dir); + } + else { + install_prefix = g_strdup(progfile_dir); + running_in_build_directory_flag = TRUE; + } +#endif /* __MINGW64__ */ + + return NULL; +} + +#else /* !_WIN32 */ + +char * +configuration_init_posix(const char* arg0) +{ const char *execname; char *prog_pathname; char *curdir; @@ -865,6 +897,18 @@ configuration_init( g_free(prog_pathname); return retstr; } +} +#endif /* ?_WIN32 */ + +char * +configuration_init(const char* arg0, const char *namespace_name) +{ + set_configuration_namespace(namespace_name); + +#ifdef _WIN32 + return configuration_init_w32(arg0); +#else + return configuration_init_posix(arg0); #endif } @@ -918,7 +962,13 @@ get_datafile_dir(void) if (datafile_dir != NULL) return datafile_dir; -#ifdef _WIN32 +#if defined(__MINGW64__) + if (running_in_build_directory_flag) { + datafile_dir = g_strdup(install_prefix); + } else { + datafile_dir = g_build_filename(install_prefix, DATA_DIR, (gchar *)NULL); + } +#elif defined(_WIN32) /* * Do we have the pathname of the program? If so, assume we're * running an installed version of the program. If we fail, @@ -1020,7 +1070,13 @@ static void init_plugin_dir(void) { #if defined(HAVE_PLUGINS) || defined(HAVE_LUA) -#ifdef _WIN32 +#if defined(__MINGW64__) + if (running_in_build_directory_flag) { + plugin_dir = g_build_filename(install_prefix, "plugins", (gchar *)NULL); + } else { + plugin_dir = g_build_filename(install_prefix, PLUGIN_DIR, (gchar *)NULL); + } +#elif defined(_WIN32) /* * On Windows, the data file directory is the installation * directory; the plugins are stored under it. @@ -1166,7 +1222,9 @@ get_plugins_pers_dir_with_version(void) */ static char *extcap_dir = NULL; -static void init_extcap_dir(void) { +static void +init_extcap_dir(void) +{ const char *extcap_dir_envar = CONFIGURATION_ENVIRONMENT_VARIABLE("EXTCAP_DIR"); if (g_getenv(extcap_dir_envar) && !started_with_special_privs()) { /* @@ -1175,7 +1233,14 @@ static void init_extcap_dir(void) { */ extcap_dir = g_strdup(g_getenv(extcap_dir_envar)); } -#ifdef _WIN32 + +#if defined(__MINGW64__) + else if (running_in_build_directory_flag) { + extcap_dir = g_build_filename(install_prefix, "extcap", (gchar *)NULL); + } else { + extcap_dir = g_build_filename(install_prefix, EXTCAP_DIR, (gchar *)NULL); + } +#elif defined(_WIN32) else { /* * On Windows, the data file directory is the installation @@ -2519,6 +2584,10 @@ free_progdirs(void) persconfprofile = NULL; g_free(progfile_dir); progfile_dir = NULL; +#ifdef __MINGW64__ + g_free(install_prefix); + install_prefix = NULL; +#endif #if defined(HAVE_PLUGINS) || defined(HAVE_LUA) g_free(plugin_dir); plugin_dir = NULL;