Skip to content

Commit

Permalink
build: Generate a .def file for Visual Studio-like builds
Browse files Browse the repository at this point in the history
This way, we can export all the non-static symbols from the appstream DLL that
we are trying to build, without touching the headers too much, by using the
dumpbin tool that comes with every installation of Visual Studio, which clang-cl
uses.

Sadly, this approach does not allow us to effectively filter out those we mark
with the GCC hidden visibility atribute, so this is the best we can do.
  • Loading branch information
fanc999-1 committed Oct 30, 2023
1 parent 5d530a0 commit 8a257bc
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 0 deletions.
116 changes: 116 additions & 0 deletions src/gen-def.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/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':
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))
16 changes: 16 additions & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,27 @@ as_deps = [

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@',
]
)
endif

appstream_lib = library ('appstream',
link_whole: as_libs,
soversion: as_api_level,
version: as_version,
dependencies: as_deps,
vs_module_defs: as_def,
install: true
)

Expand Down

0 comments on commit 8a257bc

Please sign in to comment.