Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support building for Windows with clang-cl #541

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
31 changes: 19 additions & 12 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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
#
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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'])
Expand All @@ -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
Expand Down
8 changes: 7 additions & 1 deletion src/as-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,15 @@

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>

#ifdef G_OS_WIN32
#include <io.h>
#else
#include <unistd.h>
#endif

#include <xmlb.h>

#include "as-utils-private.h"
Expand Down
6 changes: 2 additions & 4 deletions src/as-desktop-entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 */
3 changes: 3 additions & 0 deletions src/as-distro-extras.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@
#include <gio/gio.h>
#include <glib/gi18n-lib.h>
#include <errno.h>

#ifndef G_OS_WIN32
#include <unistd.h>
#endif

#include "as-utils.h"
#include "as-utils-private.h"
Expand Down
19 changes: 19 additions & 0 deletions src/as-macros-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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.
Expand Down Expand Up @@ -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 */
4 changes: 4 additions & 0 deletions src/as-pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@
#include <glib/gi18n-lib.h>
#include <stdlib.h>
#include <sys/stat.h>

#ifndef G_OS_WIN32
#include <unistd.h>
#endif

#include <errno.h>

#include "as-utils.h"
Expand Down
2 changes: 1 addition & 1 deletion src/as-system-info.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
#else
#include <sys/utsname.h>
#endif
#include <dirent.h>
#include <glib.h>

#if defined(__linux__)
#include <dirent.h>
#include <sys/sysinfo.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
#include <sys/types.h>
Expand Down
8 changes: 7 additions & 1 deletion src/as-utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <time.h>
#include <utime.h>
#ifdef G_OS_WIN32
#include <windows.h>
#include <io.h>
#include <sys/utime.h>
#else
#include <utime.h>
#include <sys/utsname.h>
#endif
#include <sys/stat.h>
Expand Down Expand Up @@ -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
}

/**
Expand Down
126 changes: 126 additions & 0 deletions src/gen-def.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/usr/bin/python3
# pylint: disable=invalid-name,missing-docstring
#
# Copyright (C) 2023 Chun-wei Fan <[email protected]>
#
# 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))
55 changes: 46 additions & 9 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand Down
Loading