diff --git a/meson.build b/meson.build index 1b78799d..a06ab44f 100644 --- a/meson.build +++ b/meson.build @@ -18,6 +18,9 @@ as_minor_version = varr[1] as_micro_version = varr[2] as_data_installdir = get_option('prefix') / get_option('datadir') / 'appstream' +# Are we building for Windows? +is_windows = host_machine.system() == 'windows' + # # Configure files # @@ -78,7 +81,7 @@ if get_option('maintainer') add_project_arguments(maintainer_c_args, language: 'cpp') endif -if get_option('static-analysis') and host_machine.system() != 'windows' +if get_option('static-analysis') and not is_windows if cc.get_id() != 'gcc' error('You need to compile with GCC to run the static analyzer!') endif @@ -165,9 +168,9 @@ add_project_arguments('-DAS_COMPILATION', language: 'c') glib_dep = dependency('glib-2.0', version: '>= 2.62') gobject_dep = dependency('gobject-2.0', version: '>= 2.62') gio_dep = dependency('gio-2.0', version: '>= 2.62') -curl_dep = dependency('libcurl', version: '>= 7.62') -xml2_dep = dependency('libxml-2.0') -yaml_dep = dependency('yaml-0.1') +curl_dep = dependency(['libcurl', 'CURL'], version: '>= 7.62') +xml2_dep = dependency(['libxml-2.0', 'LibXML2']) +yaml_dep = dependency(['yaml-0.1', 'yaml']) xmlb_dep = dependency('xmlb', version: '>= 0.3.14', fallback: ['libxmlb', 'libxmlb_dep'], default_options: ['gtkdoc=false', 'introspection=false']) @@ -188,17 +191,21 @@ if get_option ('gir') dependency('gobject-introspection-1.0', version: '>=1.56') endif +stemmer_header_found = false stemmer_inc_dirs = include_directories() if get_option('stemming') - stemmer_lib = cc.find_library('stemmer', required: true) - stemmer_inc_dirs = include_directories(['/usr/include']) - if not cc.has_header('libstemmer.h') - if cc.has_header('libstemmer/libstemmer.h') - stemmer_inc_dirs = include_directories('/usr/include/libstemmer') - else - error('Unable to find Snowball header "libstemmer.h". Please ensure libstemmer/Snowball is installed properly in order to continue.') - endif + stemmer_h = 'libstemmer.h' + usr_include_dir = '/usr/include' + fs = import('fs') + if fs.is_dir(usr_include_dir) + stemmer_inc_dirs = include_directories([usr_include_dir]) + if fs.is_file(join_paths(usr_include_dir, 'libstemmer', stemmer_h)) + stemmer_inc_dirs = include_directories( + [join_paths(usr_include_dir, 'libstemmer')] + ) + endif endif + stemmer_lib = cc.find_library('stemmer', has_headers: [stemmer_h]) endif # use gperf for faster string -> enum matching diff --git a/src/as-cache.c b/src/as-cache.c index c1808181..425476aa 100644 --- a/src/as-cache.c +++ b/src/as-cache.c @@ -34,9 +34,15 @@ #include #include -#include #include #include + +#ifdef G_OS_WIN32 +#include +#else +#include +#endif + #include #include "as-utils-private.h" diff --git a/src/as-desktop-entry.h b/src/as-desktop-entry.h index 7b957317..bdfd76f7 100644 --- a/src/as-desktop-entry.h +++ b/src/as-desktop-entry.h @@ -27,8 +27,7 @@ #include "as-metadata.h" #include "as-utils-private.h" -G_BEGIN_DECLS -#pragma GCC visibility push(hidden) +AS_BEGIN_PRIVATE_DECLS typedef GPtrArray *(*AsTranslateDesktopTextFn) (const GKeyFile *de, const gchar *text, @@ -54,7 +53,6 @@ gboolean as_desktop_entry_parse_file (AsComponent *cpt, gpointer user_data, GError **error); -#pragma GCC visibility pop -G_END_DECLS +AS_END_PRIVATE_DECLS #endif /* __AS_DESKTOP_ENTRY_H */ diff --git a/src/as-distro-extras.c b/src/as-distro-extras.c index 25e2c5ee..c236b329 100644 --- a/src/as-distro-extras.c +++ b/src/as-distro-extras.c @@ -34,7 +34,10 @@ #include #include #include + +#ifndef G_OS_WIN32 #include +#endif #include "as-utils.h" #include "as-utils-private.h" diff --git a/src/as-macros-private.h b/src/as-macros-private.h index 3f00aee9..9c4d8ba3 100644 --- a/src/as-macros-private.h +++ b/src/as-macros-private.h @@ -26,6 +26,20 @@ #include "as-macros.h" G_BEGIN_DECLS + +#ifdef _MSC_VER + +#define AS_BEGIN_PRIVATE_DECLS G_BEGIN_DECLS +#define AS_END_PRIVATE_DECLS G_END_DECLS + +#ifdef AS_STATIC +# define AS_INTERNAL_VISIBLE +#else +# define AS_INTERNAL_VISIBLE __declspec(dllexport) +#endif + +#else + #pragma GCC visibility push(hidden) #define AS_BEGIN_PRIVATE_DECLS \ @@ -36,6 +50,8 @@ G_BEGIN_DECLS #define AS_INTERNAL_VISIBLE __attribute__((visibility("default"))) +#endif + /** * as_str_equal0: * Returns TRUE if strings are equal, ignoring NULL strings. @@ -107,7 +123,10 @@ G_BEGIN_DECLS } \ G_STMT_END +#ifndef _MSC_VER #pragma GCC visibility pop +#endif + G_END_DECLS #endif /* __AS_MACROS_PRIVATE_H */ diff --git a/src/as-pool.c b/src/as-pool.c index 9b5c8bf9..a38f7460 100644 --- a/src/as-pool.c +++ b/src/as-pool.c @@ -48,7 +48,11 @@ #include #include #include + +#ifndef G_OS_WIN32 #include +#endif + #include #include "as-utils.h" diff --git a/src/as-system-info.c b/src/as-system-info.c index de9b731d..0dd9ec5b 100644 --- a/src/as-system-info.c +++ b/src/as-system-info.c @@ -44,10 +44,10 @@ #else #include #endif -#include #include #if defined(__linux__) +#include #include #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) #include diff --git a/src/as-utils.c b/src/as-utils.c index 218f1774..6ba096cd 100644 --- a/src/as-utils.c +++ b/src/as-utils.c @@ -32,10 +32,12 @@ #include #include #include -#include #ifdef G_OS_WIN32 #include +#include +#include #else +#include #include #endif #include @@ -967,7 +969,11 @@ as_touch_location (const gchar *fname) void as_reset_umask (void) { +#ifdef G_OS_WIN32 + umask (S_IREAD | S_IWRITE); +#else umask (0022); +#endif } /** diff --git a/src/gen-def.py b/src/gen-def.py new file mode 100644 index 00000000..6202aeb2 --- /dev/null +++ b/src/gen-def.py @@ -0,0 +1,126 @@ +#!/usr/bin/python3 +# pylint: disable=invalid-name,missing-docstring +# +# Copyright (C) 2023 Chun-wei Fan +# +# SPDX-License-Identifier: LGPL-2.1+ + +# Script to generate .def file from object files/static library + +import argparse +import os +import re +import subprocess +import sys + +from io import StringIO + + +def run_dumpbin(objs): + dumpbin_results = [] + for o in objs: + command = ['dumpbin', '/symbols', o] + p = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=None, + stdin=subprocess.PIPE, + universal_newlines=True, + ) + stdout, blah = p.communicate() + if p.returncode != 0: + sys.exit(p.returncode) + dumpbin_results.append(stdout) + + return dumpbin_results + +''' +Notice output from dumpbin /symbols is like the following: + +Microsoft (R) COFF/PE Dumper Version 14.29.30152.0 +Copyright (C) Microsoft Corporation. All rights reserved. + + +Dump of file src\libappstream-5-core.a + +File Type: LIBRARY + +COFF SYMBOL TABLE +000 00000000 SECT1 notype Static | .text + Section length 0, #relocs 0, #linenums 0, checksum 0 +002 00000000 SECT2 notype Static | .data + Section length 0, #relocs 0, #linenums 0, checksum 0 +004 00000000 SECT3 notype Static | .bss + Section length 18, #relocs 0, #linenums 0, checksum 0 +006 00000000 SECT4 notype Static | .text + Section length 36, #relocs 6, #linenums 0, checksum 11750A74, selection 1 (pick no duplicates) +008 00000000 SECT4 notype () External | as_video_get_type +009 00000000 SECT32 notype Static | .xdata +... + +So, we are only more interested in items like: + +008 00000000 SECT4 notype () External | as_video_get_type + +and we need to note that these can also involve symbols that we use from +other libraries, so we throw these out when we go through the output +''' + +def extract_symbols(namespace, tokens): + if tokens[4] == '()': + check_idx = 5 + target_idx = 7 + else: + check_idx = 4 + target_idx = 6 + + if tokens[check_idx] == 'External': + target_plat = None + if 'Platform' in os.environ: + target_plat = os.environ['Platform'] + use_sym_prefix = False + if target_plat is not None and target_plat == 'x86': + use_sym_prefix = True + if use_sym_prefix: + if re.match(r'^' + '_' + namespace + '_', tokens[target_idx]) is not None: + return tokens[target_idx][1:] + else: + if re.match(r'^' + namespace + '_', tokens[target_idx]) is not None: + return tokens[target_idx] + +def process_dumpbin_outputs(namespace, dumpbin_results): + extracted_symbols = [] + for res in dumpbin_results: + dumpbin_lines = StringIO(res).readlines() + for l in dumpbin_lines: + tokens = l.split() + if (len(tokens) == 7 or len(tokens) == 8) and tokens[3] == 'notype': + result = extract_symbols(namespace, tokens) + if result is not None: + extracted_symbols.append(result) + extracted_symbols.sort() + return extracted_symbols + + +def output_def_file(def_file, symbols): + with open(def_file, "w") as out: + out.write("EXPORTS\n") + for s in symbols: + out.write("%s\n" % s) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Generate .def from object files or static libs.') + parser.add_argument('-n', '--namespace', dest='namespace', + help='namespace of symbols', required=True) + parser.add_argument('--def', dest='def_file', required=True, + help='output def file') + parser.add_argument('objects', nargs='+', + help='objects files/static libraries to process') + + args = parser.parse_args() + namespace = args.namespace + def_file = args.def_file + objs = args.objects + dumpbin_results = run_dumpbin(objs) + output_def_file(def_file, process_dumpbin_outputs(namespace, dumpbin_results)) diff --git a/src/meson.build b/src/meson.build index ef5c6288..bf66df79 100644 --- a/src/meson.build +++ b/src/meson.build @@ -196,18 +196,55 @@ if get_option ('stemming') aslib_deps += [stemmer_lib] endif +# We need this target to use dumpbin to generate a .def file +as_core_lib = static_library('appstream-@0@-'.format(as_api_level) + 'core', [ + aslib_src, + aslib_pub_headers, + aslib_gir_headers, + aslib_priv_headers, + aslib_res, + aslib_pub_enums, + ], + include_directories: [stemmer_inc_dirs, root_inc_dir], + dependencies: [aslib_deps], + install: false +) + +as_core_dep = declare_dependency( + link_with: as_core_lib, + include_directories: [stemmer_inc_dirs, root_inc_dir], + dependencies: [aslib_deps], +) + +as_deps = [ + as_core_dep, +] + +as_libs = [as_core_lib] + +if is_windows and cc.get_argument_syntax() == 'msvc' + gen_def = find_program('gen-def.py') + as_def = custom_target( + 'Generate Windows .def file', + input: as_core_lib, + output: 'appstream.def', + command: [ + gen_def, + '-n', 'as', + '--def', '@OUTPUT@', + '@INPUT@', + ] + ) +else + as_def = [] +endif + appstream_lib = library ('appstream', - [aslib_src, - aslib_pub_headers, - aslib_gir_headers, - aslib_priv_headers, - aslib_res, - aslib_pub_enums], + link_whole: as_libs, soversion: as_api_level, version: as_version, - dependencies: [aslib_deps], - include_directories: [stemmer_inc_dirs, - root_inc_dir], + dependencies: as_deps, + vs_module_defs: as_def, install: true ) diff --git a/tools/ascli-actions-pkgmgr.c b/tools/ascli-actions-pkgmgr.c index 690ae31b..1938c9a4 100644 --- a/tools/ascli-actions-pkgmgr.c +++ b/tools/ascli-actions-pkgmgr.c @@ -22,7 +22,11 @@ #include #include + +#ifndef G_OS_WIN32 #include +#endif + #include #include "ascli-utils.h" @@ -41,6 +45,12 @@ exec_pm_action (const gchar *action, gchar **pkgnames) const gchar *exe = NULL; g_auto(GStrv) cmd = NULL; +#ifdef G_OS_WIN32 + g_printerr ("%s\n", + _("No supported package managers are available on Windows.")); + return ASCLI_EXIT_CODE_FAILED; +#else + #ifdef HAVE_APT_SUPPORT if (g_file_test ("/usr/bin/apt", G_FILE_TEST_EXISTS)) exe = "/usr/bin/apt"; @@ -66,6 +76,7 @@ exec_pm_action (const gchar *action, gchar **pkgnames) if (ret != 0) ascli_print_stderr (_("Unable to spawn package manager: %s"), g_strerror (errno)); return ret; +#endif } /** @@ -80,6 +91,12 @@ exec_flatpak_action (const gchar *action, const gchar *bundle_id) const gchar *exe = NULL; g_auto(GStrv) cmd = NULL; +#ifdef G_OS_WIN32 + g_printerr ("%s\n", + _("Flatpak is unavailable on Windows.")); + return ASCLI_EXIT_CODE_FAILED; +#else + exe = "/usr/bin/flatpak"; if (!g_file_test (exe, G_FILE_TEST_EXISTS)) { g_printerr ("%s\n", _("Flatpak was not found! Please install it to continue.")); @@ -95,6 +112,7 @@ exec_flatpak_action (const gchar *action, const gchar *bundle_id) if (ret != 0) ascli_print_stderr (_("Unable to spawn Flatpak process: %s"), g_strerror (errno)); return ret; +#endif } static int diff --git a/tools/ascli-utils.c b/tools/ascli-utils.c index 99e8617b..b947460b 100644 --- a/tools/ascli-utils.c +++ b/tools/ascli-utils.c @@ -22,9 +22,12 @@ #include #include -#include #include +#ifndef G_OS_WIN32 +#include +#endif + #include "as-pool-private.h" /**