Browse Source

WIP: Switch to Meson

zrythm_meson
David Robillard 2 years ago
parent
commit
ee0a469112
  1. 2
      .gitignore
  2. 199
      .gitlab-ci.yml
  3. 3
      .gitmodules
  4. 1
      doc/_static/meson.build
  5. 8
      doc/c/Doxyfile.in
  6. 5
      doc/c/api/meson.build
  7. 38
      doc/c/meson.build
  8. 41
      doc/c/wscript
  9. 19
      doc/c/xml/meson.build
  10. 4
      doc/conf.py.in
  11. 17
      doc/meson.build
  12. 188
      meson.build
  13. 196
      meson/meson.build
  14. 11
      meson_options.txt
  15. 11
      serd.pc.in
  16. 167
      test/meson.build
  17. 21
      test/test_quiet.py
  18. 38
      test/test_stdin.py
  19. 31
      test/test_write_error.py
  20. 27
      waf
  21. 1
      waflib
  22. 506
      wscript

2
.gitignore vendored

@ -1,4 +1,2 @@ @@ -1,4 +1,2 @@
build/**
.waf-*
.lock-waf*
__pycache__

199
.gitlab-ci.yml

@ -1,228 +1,157 @@ @@ -1,228 +1,157 @@
stages: [build, test, deploy]
variables:
GIT_SUBMODULE_STRATEGY: normal
stages:
- build
- deploy
.build_template: &build_definition
stage: build
artifacts:
paths: ["build/", ".lock-waf*"]
.test_template: &test_definition
stage: test
artifacts:
paths: [build/coverage]
arm32_dbg:
<<: *build_definition
image: lv2plugin/debian-arm32
script: python ./waf configure build -dST --werror
variables:
CC: "arm-linux-gnueabihf-gcc"
CXX: "arm-linux-gnueabihf-g++"
test:arm32_dbg:
<<: *test_definition
image: lv2plugin/debian-arm32
script: python ./waf test --wrapper=qemu-arm
needs: ["arm32_dbg"]
script:
- meson setup build --cross-file=/usr/share/meson/cross/arm-linux-gnueabihf.ini -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
arm32_rel:
<<: *build_definition
image: lv2plugin/debian-arm32
script: python ./waf configure build -ST --werror
variables:
CC: "arm-linux-gnueabihf-gcc"
CXX: "arm-linux-gnueabihf-g++"
test:arm32_rel:
<<: *test_definition
image: lv2plugin/debian-arm32
script: python ./waf test --wrapper=qemu-arm
needs: ["arm32_rel"]
script:
- meson setup build --cross-file=/usr/share/meson/cross/arm-linux-gnueabihf.ini -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
arm64_dbg:
<<: *build_definition
image: lv2plugin/debian-arm64
script: python ./waf configure build -dST --werror
variables:
CC: "aarch64-linux-gnu-gcc"
CXX: "aarch64-linux-gnu-g++"
test:arm64_dbg:
<<: *test_definition
image: lv2plugin/debian-arm64
script: python ./waf test --wrapper=qemu-aarch64
needs: ["arm64_dbg"]
script:
- meson setup build --cross-file=/usr/share/meson/cross/aarch64-linux-gnu.ini -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
arm64_rel:
<<: *build_definition
image: lv2plugin/debian-arm64
script: python ./waf configure build -ST --werror
variables:
CC: "aarch64-linux-gnu-gcc"
CXX: "aarch64-linux-gnu-g++"
test:arm64_rel:
<<: *test_definition
image: lv2plugin/debian-arm64
script: python ./waf test --wrapper=qemu-aarch64
needs: ["arm64_rel"]
script:
- meson setup build --cross-file=/usr/share/meson/cross/aarch64-linux-gnu.ini -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
x64_dbg:
<<: *build_definition
image: lv2plugin/debian-x64
script: python ./waf configure build -dST --werror --docs
test:x64_dbg:
<<: *test_definition
image: lv2plugin/debian-x64
script:
- python ./waf test
- cp doc/*.svg build/doc/
- groff -Thtml -P -l -P -r -man -wall doc/serdi.1 > build/doc/serdi.html
needs: ["x64_dbg"]
- meson setup build -Dbuildtype=debug -Ddocs=enabled -Dstrict=true -Dwerror=true
- ninja -C build test
artifacts:
paths:
- build/doc
- build/coverage
x64_rel:
<<: *build_definition
image: lv2plugin/debian-x64
script: python ./waf configure build -ST --werror
test:x64_rel:
<<: *test_definition
image: lv2plugin/debian-x64
script: python ./waf test
needs: ["x64_rel"]
script:
- meson setup build -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
x64_static:
<<: *build_definition
image: lv2plugin/debian-x64
script: python ./waf configure build -ST --werror --no-posix --static-progs
test:x64_static:
<<: *test_definition
image: lv2plugin/debian-x64
script: python ./waf test
needs: ["x64_static"]
script:
- meson setup build -Ddefault_library=static -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
x64_sanitize:
<<: *build_definition
image: lv2plugin/debian-x64-clang
script:
- python ./waf configure build -ST --werror --no-coverage
- python ./waf test
- meson setup build -Db_lundef=false -Dbuildtype=plain -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
variables:
CC: "clang"
CFLAGS: "-fno-sanitize-recover=all -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds -fsanitize=nullability"
CXX: "clang++"
CFLAGS: "-fno-sanitize-recover=all -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds -fsanitize=nullability"
CXXFLAGS: "-fno-sanitize-recover=all -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds -fsanitize=nullability"
LINKFLAGS: "-fno-sanitize-recover=all -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds -fsanitize=nullability"
LDFLAGS: "-fno-sanitize-recover=all -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds -fsanitize=nullability"
mingw32_dbg:
<<: *build_definition
image: lv2plugin/debian-mingw32
script: python ./waf configure build -dST --werror --no-coverage
script:
- meson setup build --cross-file=/usr/share/meson/cross/i686-w64-mingw32.ini -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
variables:
CC: "i686-w64-mingw32-gcc"
CXX: "i686-w64-mingw32-g++"
MESON_TESTTHREADS: "1"
WINEPATH: "Z:\\usr\\lib\\gcc\\i686-w64-mingw32\\8.3-win32"
mingw32_rel:
<<: *build_definition
image: lv2plugin/debian-mingw32
script: python ./waf configure build -ST --werror --no-coverage
script:
- meson setup build --cross-file=/usr/share/meson/cross/i686-w64-mingw32.ini -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
variables:
CC: "i686-w64-mingw32-gcc"
CXX: "i686-w64-mingw32-g++"
MESON_TESTTHREADS: "1"
WINEPATH: "Z:\\usr\\lib\\gcc\\i686-w64-mingw32\\8.3-win32"
mingw64_dbg:
<<: *build_definition
image: lv2plugin/debian-mingw64
script: python ./waf configure build -dST --werror --no-coverage
script:
- meson setup build --cross-file=/usr/share/meson/cross/x86_64-w64-mingw32.ini -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
variables:
CC: "x86_64-w64-mingw32-gcc"
CXX: "x86_64-w64-mingw32-g++"
MESON_TESTTHREADS: "1"
mingw64_rel:
<<: *build_definition
image: lv2plugin/debian-mingw64
script: python ./waf configure build -ST --werror --no-coverage
script:
- meson setup build --cross-file=/usr/share/meson/cross/x86_64-w64-mingw32.ini -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
variables:
CC: "x86_64-w64-mingw32-gcc"
CXX: "x86_64-w64-mingw32-g++"
MESON_TESTTHREADS: "1"
mac_dbg:
<<: *build_definition
script: python ./waf configure build -dST --werror --no-coverage
tags: [macos]
test:mac_dbg:
<<: *test_definition
script: python ./waf test
needs: ["mac_dbg"]
tags: [macos]
script:
- meson setup build -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
mac_rel:
<<: *build_definition
script: python ./waf configure build -ST --werror --no-coverage
tags: [macos]
test:mac_rel:
<<: *test_definition
script: python ./waf test
needs: ["mac_rel"]
tags: [macos]
script:
- meson setup build -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
win_dbg:
<<: *build_definition
script: python ./waf configure build -dST --werror --no-coverage
tags: [windows,msvc,python]
test:win_dbg:
<<: *test_definition
script: python ./waf test
needs: ["win_dbg"]
tags: [windows,msvc,python]
tags: [windows,meson]
script:
- meson setup build -Dbuildtype=debug -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
win_rel:
<<: *build_definition
script: python ./waf configure build -ST --werror --no-coverage
tags: [windows,msvc,python]
test:win_rel:
<<: *test_definition
script: python ./waf test
needs: ["win_rel"]
tags: [windows,msvc,python]
tags: [windows,meson]
script:
- meson setup build -Dbuildtype=release -Ddocs=disabled -Dstrict=true -Dwerror=true
- ninja -C build test
pages:
stage: deploy
script:
- mkdir -p .public/doc
- mkdir -p .public/man
- mkdir -p .public/c
- mv build/doc/c/singlehtml .public/c/singlehtml
- mv build/doc/c/html .public/c/html
- mv build/doc/serdi.html .public/man/serdi.html
- mv .public public
- mkdir public
- mkdir public/c
- mv build/doc/c/singlehtml/ public/c/singlehtml/
dependencies:
- x64_dbg
artifacts:
paths:
- public

3
.gitmodules vendored

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
[submodule "waflib"]
path = waflib
url = ../autowaf.git

1
doc/_static/meson.build vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
configure_file(copy: true, input: '../../resources/serd.svg', output: 'serd.svg')

8
doc/c/Doxyfile → doc/c/Doxyfile.in

@ -2,12 +2,13 @@ PROJECT_NAME = Serd @@ -2,12 +2,13 @@ PROJECT_NAME = Serd
PROJECT_BRIEF = "A lightweight library for RDF storage and serialisation"
QUIET = YES
WARN_AS_ERROR = NO
WARN_AS_ERROR = YES
WARN_IF_UNDOCUMENTED = NO
WARN_NO_PARAMDOC = NO
JAVADOC_AUTOBRIEF = YES
FULL_PATH_NAMES = NO
CASE_SENSE_NAMES = YES
HIDE_IN_BODY_DOCS = YES
REFERENCES_LINK_SOURCE = NO
@ -28,6 +29,7 @@ PREDEFINED = SERD_ALLOCATED \ @@ -28,6 +29,7 @@ PREDEFINED = SERD_ALLOCATED \
SERD_NULLABLE= \
SERD_PURE_FUNC=
INPUT = ../../include/serd/serd.h
STRIP_FROM_PATH = @SERD_SRCDIR@
INPUT = @SERD_HEADERS@
OUTPUT_DIRECTORY = .
OUTPUT_DIRECTORY = doc/c

5
doc/c/api/meson.build

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
c_serd_rst = custom_target(
'C API ReST Documentation',
command: [dox_to_sphinx, '-f', '@INPUT0@', 'doc/c/api'],
input: [c_index_xml] + c_rst_files,
output: 'serd.rst')

38
doc/c/meson.build

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
config = configuration_data()
config.set('SERD_VERSION', meson.project_version())
conf_py = configure_file(configuration: config,
input: '../conf.py.in',
output: 'conf.py')
configure_file(copy: true, input: '../summary.rst', output: 'summary.rst')
c_rst_files = files(
'index.rst',
'overview.rst',
)
foreach f : c_rst_files
configure_file(copy: true, input: f, output: '@PLAINNAME@')
endforeach
subdir('xml')
subdir('api')
docs = custom_target(
'C API Documentation (singlehtml)',
command: [sphinx_build, '-M', 'singlehtml', 'doc/c/', 'doc/c/', '-E', '-q', '-t', 'singlehtml'],
input: [c_rst_files, c_serd_rst, c_index_xml],
output: 'singlehtml',
build_by_default: true,
install: true,
install_dir: docdir / 'serd-0')
docs = custom_target(
'C API Documentation (html)',
command: [sphinx_build, '-M', 'html', 'doc/c/', 'doc/c/', '-E', '-q', '-t', 'html'],
input: [c_rst_files, c_serd_rst, c_index_xml],
output: 'html',
build_by_default: true,
install: true,
install_dir: docdir / 'serd-0')

41
doc/c/wscript

@ -1,41 +0,0 @@ @@ -1,41 +0,0 @@
#!/usr/bin/env python
def build(bld):
dox_to_sphinx = bld.path.find_node("../../scripts/dox_to_sphinx.py")
index_xml = bld.path.get_bld().make_node("xml/index.xml")
files = [
("../../resources/serd.svg", "sphinx/_static/serd.svg"),
("../summary.rst", "sphinx/summary.rst"),
("index.rst", "sphinx/index.rst"),
("overview.rst", "sphinx/overview.rst"),
]
# Run Doxygen to generate XML documentation
bld(features="doxygen", doxyfile="Doxyfile")
# Substitute variables to make Sphinx configuration file
bld(features="subst",
source="../conf.py.in",
target="sphinx/conf.py",
SERD_VERSION=bld.env.SERD_VERSION)
# Copy static documentation files to Sphinx build directory
for f in files:
bld(features="subst", is_copy=True, source=f[0], target=f[1])
# Generate Sphinx markup from Doxygen XML
bld.add_group()
bld(rule="${PYTHON} " + dox_to_sphinx.abspath() + " -f ${SRC} ${TGT}",
source=index_xml,
target="sphinx/api/")
doc_dir = bld.env.DOCDIR + "/serd-%s/" % bld.env.SERD_MAJOR_VERSION
# Run Sphinx to generate HTML documentation
for builder in ["html", "singlehtml"]:
bld(features="sphinx",
sphinx_source=bld.path.get_bld().make_node("sphinx"),
sphinx_output_format=builder,
sphinx_options=["-E", "-q", "-t", builder],
install_path=doc_dir + "c/%s/" % builder)

19
doc/c/xml/meson.build

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
doxygen = find_program('doxygen')
c_doxygen_input = []
foreach h : c_headers
c_doxygen_input += ['..' / h]
endforeach
config = configuration_data()
config.set('SERD_HEADERS', ' '.join(c_doxygen_input))
config.set('SERD_SRCDIR', serd_src_root)
c_doxyfile = configure_file(configuration: config,
input: '../Doxyfile.in',
output: 'Doxyfile')
c_index_xml = custom_target('c-index.xml',
command: [doxygen, '@INPUT0@'],
input: [c_doxyfile] + c_header_files,
output: 'index.xml')

4
doc/conf.py.in

@ -41,10 +41,10 @@ nitpick_ignore = list(map(lambda x: ("c:identifier", x), _opaque)) @@ -41,10 +41,10 @@ nitpick_ignore = list(map(lambda x: ("c:identifier", x), _opaque))
# HTML output
html_static_path = ["_static"]
html_theme = "sphinx_lv2_theme"
html_copy_source = False
html_short_title = "Serd"
html_static_path = ["../_static"]
html_theme = "sphinx_lv2_theme"
if tags.has('singlehtml'):
html_sidebars = {

17
doc/meson.build

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
docdir = get_option('datadir') / 'doc'
doxygen = find_program('doxygen', required: get_option('docs'))
dox_to_sphinx = find_program('../scripts/dox_to_sphinx.py')
sphinx_build = find_program('sphinx-build', required: get_option('docs'))
build_docs = doxygen.found() and sphinx_build.found()
if build_docs
subdir('_static')
subdir('c')
endif
if meson.version().version_compare('>=0.53.0')
summary('Documentation', build_docs, bool_yn: true)
endif

188
meson.build

@ -0,0 +1,188 @@ @@ -0,0 +1,188 @@
project('serd', ['c'],
version: '0.30.9',
license: 'ISC',
meson_version: '>= 0.49.2',
default_options: [
'b_ndebug=if-release',
'buildtype=release',
'c_std=c99',
'default_library=shared',
'warning_level=2',
])
serd_src_root = meson.current_source_dir()
major_version = meson.project_version().split('.')[0]
version_suffix = '-@0@'.format(major_version)
versioned_name = 'serd' + version_suffix
# Load build tools
pkg = import('pkgconfig')
cc = meson.get_compiler('c')
# Set ultra strict warnings for developers, if requested
if get_option('strict')
subdir('meson')
c_warnings = all_c_warnings
if cc.get_id() == 'clang'
c_warnings += [
'-Wno-bad-function-cast',
'-Wno-cast-align',
'-Wno-cast-qual',
'-Wno-conversion',
'-Wno-covered-switch-default',
'-Wno-disabled-macro-expansion',
'-Wno-double-promotion',
'-Wno-format-nonliteral',
'-Wno-implicit-fallthrough',
'-Wno-nullability-extension',
'-Wno-nullable-to-nonnull-conversion',
'-Wno-padded',
'-Wno-reserved-id-macro',
'-Wno-sign-conversion',
]
elif cc.get_id() == 'gcc'
c_warnings += [
'-Wno-bad-function-cast',
'-Wno-cast-align',
'-Wno-cast-qual',
'-Wno-float-conversion',
'-Wno-format-nonliteral',
'-Wno-inline',
'-Wno-padded',
'-Wno-sign-conversion',
'-Wno-switch-default',
'-Wno-unsuffixed-float-constants',
'-Wno-unused-const-variable',
]
elif cc.get_id() == 'msvc'
c_warnings += [
'/wd4061', # enumerator in switch is not explicitly handled
'/wd4365', # signed/unsigned mismatch
'/wd4514', # unreferenced inline function has been removed
'/wd4706', # assignment within conditional expression
'/wd4710', # function not inlined
'/wd4711', # function selected for automatic inline expansion
'/wd4820', # padding added after construct
'/wd4996', # POSIX name for this item is deprecated
'/wd5045', # will insert Spectre mitigation for memory load
]
endif
add_project_arguments(cc.get_supported_arguments(c_warnings),
language: ['c'])
endif
# Add special arguments for MSVC
if cc.get_id() == 'msvc'
msvc_args = [
'/D_CRT_SECURE_NO_WARNINGS',
'/TP',
'/experimental:external',
'/external:W0',
'/external:anglebrackets',
]
add_project_arguments(msvc_args, language: ['c'])
endif
c_headers = ['include/serd/serd.h']
c_header_files = files(c_headers)
sources = [
'src/base64.c',
'src/byte_source.c',
'src/env.c',
'src/n3.c',
'src/node.c',
'src/reader.c',
'src/string.c',
'src/system.c',
'src/uri.c',
'src/writer.c',
]
# System libraries
m_dep = cc.find_library('m', required: false)
# Determine library type and the flags needed to build it
if get_option('default_library') == 'both'
if host_machine.system() == 'windows'
error('default_library=both is not supported on Windows')
endif
library_type = 'both_libraries'
library_args = ['-DSERD_INTERNAL']
prog_args = []
elif get_option('default_library') == 'shared'
library_type = 'shared_library'
library_args = ['-DSERD_INTERNAL']
prog_args = []
else
library_type = 'static_library'
library_args = ['-DSERD_INTERNAL', '-DSERD_STATIC']
prog_args = ['-DSERD_STATIC']
endif
# Build shared and/or static library/libraries
libserd = build_target(
versioned_name,
sources,
version: meson.project_version(),
include_directories: include_directories(['include']),
c_args: library_args,
dependencies: m_dep,
gnu_symbol_visibility: 'hidden',
install: true,
target_type: library_type)
serd_dep = declare_dependency(
include_directories: include_directories(['include']),
link_with: libserd)
pkg.generate(
libserd,
name: 'Serd',
filebase: versioned_name,
subdirs: [versioned_name],
version: meson.project_version(),
description: 'A lightweight library for working with RDF')
# Build serdi command line utility
if get_option('utils')
serdi = executable('serdi', 'src/serdi.c',
c_args: prog_args,
install: true,
dependencies: serd_dep)
if not get_option('docs').disabled()
install_man('doc/serdi.1')
endif
endif
# Install header to a versioned include directory
install_headers(c_headers, subdir: versioned_name / 'serd')
if not get_option('docs').disabled()
subdir('doc')
endif
if get_option('tests')
subdir('test')
endif
if meson.version().version_compare('>=0.53.0')
summary('Tests', get_option('tests'), bool_yn: true)
summary('Utilities', get_option('utils'), bool_yn: true)
summary('Install prefix', get_option('prefix'))
summary('Headers', get_option('prefix') / get_option('includedir'))
summary('Libraries', get_option('prefix') / get_option('libdir'))
if get_option('utils')
summary('Executables', get_option('prefix') / get_option('bindir'))
summary('Man pages', get_option('prefix') / get_option('mandir'))
endif
endif

196
meson/meson.build

@ -0,0 +1,196 @@ @@ -0,0 +1,196 @@
# General code to enable approximately all warnings.
#
# This is trivial for clang and MSVC, but GCC does not have such an option, and
# has several esoteric warnings, so we need to enable everything we want
# explicitly. We enable everything that does not require a value argument,
# except for warnings that are only relevant for very old languages (earlier
# than C99 or C++11) or non-standard extensions.
#
# Omitted common warnings:
#
# Wabi=
# Waggregate-return
# Walloc-size-larger-than=BYTES
# Walloca-larger-than=BYTES
# Wframe-larger-than=BYTES
# Wlarger-than=BYTES
# Wstack-usage=BYTES
# Wsystem-headers
# Wtraditional
# Wtraditional-conversion
# Wtrampolines
# Wvla-larger-than=BYTES
#
# Omitted C warnings:
#
# Wc90-c99-compat
# Wdeclaration-after-statement
# Wtraditional
# Wtraditional-conversion
#
# Omitted C++ warnings:
#
# Wnamespaces
# Wtemplates
gcc_common_warnings = [
'-Walloc-zero',
'-Walloca',
'-Wanalyzer-too-complex',
'-Warith-conversion',
'-Warray-bounds=2',
'-Wattribute-alias=2',
'-Wcast-align=strict',
'-Wcast-qual',
'-Wconversion',
'-Wdate-time',
'-Wdisabled-optimization',
'-Wdouble-promotion',
'-Wduplicated-branches',
'-Wduplicated-cond',
'-Wfloat-equal',
'-Wformat-overflow=2',
'-Wformat-signedness',
'-Wformat-truncation=2',
'-Wformat=2',
'-Wimplicit-fallthrough=2',
'-Winit-self',
'-Winline',
'-Winvalid-pch',
'-Wlogical-op',
'-Wmissing-declarations',
'-Wmissing-include-dirs',
'-Wmultichar',
'-Wnormalized=nfc',
'-Wnull-dereference',
'-Wpacked',
'-Wpadded',
'-Wredundant-decls',
'-Wscalar-storage-order',
'-Wshadow',
'-Wshift-overflow=2',
'-Wsizeof-array-argument',
'-Wstack-protector',
'-Wstrict-aliasing=3',
'-Wstrict-overflow=5',
'-Wstringop-overflow=3',
'-Wsuggest-attribute=cold',
'-Wsuggest-attribute=const',
'-Wsuggest-attribute=format',
'-Wsuggest-attribute=malloc',
'-Wsuggest-attribute=noreturn',
'-Wsuggest-attribute=pure',
'-Wswitch-default',
'-Wswitch-enum',
'-Wsync-nand',
'-Wundef',
'-Wunused-const-variable=2',
'-Wunused-macros',
'-Wvarargs',
'-Wvector-operation-performance',
'-Wvla',
'-Wwrite-strings',
]
gcc_c_warnings = [
'-Wbad-function-cast',
'-Wc++-compat',
'-Wc99-c11-compat',
'-Wdesignated-init',
'-Wdiscarded-array-qualifiers',
'-Wdiscarded-qualifiers',
'-Wincompatible-pointer-types',
'-Wjump-misses-init',
'-Wmissing-prototypes',
'-Wnested-externs',
'-Wold-style-definition',
'-Wstrict-prototypes',
'-Wunsuffixed-float-constants',
]
# Set all_c_warnings for the current C compiler
if is_variable('cc')
if cc.get_id() == 'clang'
all_c_warnings = ['-Weverything']
elif cc.get_id() == 'gcc'
all_c_warnings = gcc_common_warnings + [
'-Wbad-function-cast',
'-Wc++-compat',
'-Wc99-c11-compat',
'-Wdesignated-init',
'-Wdiscarded-array-qualifiers',
'-Wdiscarded-qualifiers',
'-Wincompatible-pointer-types',
'-Wjump-misses-init',
'-Wmissing-prototypes',
'-Wnested-externs',
'-Wold-style-definition',
'-Wstrict-prototypes',
'-Wunsuffixed-float-constants',
]
elif cc.get_id() == 'msvc'
all_c_warnings = ['/Wall']
else
all_c_warnings = []
endif
endif
# Set all_cpp_warnings for the current C++ compiler
if is_variable('cpp')
if cpp.get_id() == 'clang'
all_cpp_warnings = [
'-Weverything',
'-Wno-c++98-compat',
'-Wno-c++98-compat-pedantic'
]
elif cpp.get_id() == 'gcc'
all_cpp_warnings = gcc_common_warnings + [
'-Wabi-tag',
'-Waligned-new=all',
'-Wcatch-value=3',
'-Wcomma-subscript',
'-Wconditionally-supported',
'-Wctor-dtor-privacy',
'-Wdeprecated-copy-dtor',
'-Weffc++',
'-Wextra-semi',
'-Wmismatched-tags',
'-Wmultiple-inheritance',
'-Wnoexcept',
'-Wnoexcept-type',
'-Wnon-virtual-dtor',
'-Wold-style-cast',
'-Woverloaded-virtual',
'-Wplacement-new=2',
'-Wredundant-tags',
'-Wregister',
'-Wsign-promo',
'-Wstrict-null-sentinel',
'-Wsuggest-final-methods',
'-Wsuggest-final-types',
'-Wsuggest-override',
'-Wuseless-cast',
'-Wvirtual-inheritance',
'-Wvolatile',
'-Wzero-as-null-pointer-constant',
]
elif cpp.get_id() == 'msvc'
all_cpp_warnings = ['/Wall']
else
all_cpp_warnings = []
endif
endif
# Set all_objc_warnings for the current Objective C compiler
if is_variable('objcc')
all_objc_warnings = []
if objcc.get_id() == 'clang'
all_objc_warnings = ['-Weverything']
elif objc.get_id() == 'gcc'
all_objc_warnings = gcc_common_warnings + [
'-Wno-direct-ivar-access',
]
else
all_objc_warnings = []
endif
endif

11
meson_options.txt

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
option('docs', type: 'feature', value: 'auto', yield: true,
description: 'Build documentation')
option('strict', type: 'boolean', value: false, yield: true,
description: 'Enable ultra-strict warnings')
option('tests', type: 'boolean', value: true, yield: true,
description: 'Build tests')
option('utils', type: 'boolean', value: true, yield: true,
description: 'Build command line utilities')

11
serd.pc.in

@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
prefix=@PREFIX@
exec_prefix=@EXEC_PREFIX@
libdir=@LIBDIR@
includedir=@INCLUDEDIR@
Name: Serd
Version: @SERD_VERSION@
Description: Lightweight RDF syntax library
Libs: -L${libdir} -l@LIB_SERD@
Libs.private: -lm
Cflags: -I${includedir}/serd-@SERD_MAJOR_VERSION@

167
test/meson.build

@ -0,0 +1,167 @@ @@ -0,0 +1,167 @@
autoship = find_program('autoship', required: false)
run_test_suite = find_program('run_test_suite.py')
wrapper = meson.get_cross_property('wrapper', '')
unit_tests = [
'env',
'free_null',
'node',
'read_chunk',
'reader_writer',
'string',
'uri',
]
foreach unit : unit_tests
test(unit,
executable('test_@0@'.format(unit),
'test_@0@.c'.format(unit),
c_args: prog_args,
dependencies: serd_dep),
suite: 'unit')
endforeach
if autoship.found()
test('autoship', autoship, args: ['test', serd_src_root], suite: 'data')
endif
if get_option('utils')
if wrapper != ''
script_args = ['--wrapper', wrapper, '--serdi', serdi.full_path()]
else
script_args = ['--serdi', serdi.full_path()]
endif
serd_ttl = files('../serd.ttl')[0]
test('serd.ttl', serdi, args: [serd_ttl], suite: 'data')
# Command line options
good_args = [
['-v'],
['-h'],
['-s', '<urn:eg:s> a <urn:eg:T> .'],
]
foreach args : good_args
test(args[0], serdi, args: args, suite: ['serdi', 'options'])
endforeach
bad_args = [
['-c'],
['-i', 'unknown'],
['-i'],
['-o', 'unknown'],
['-o'],
['-p'],
['-r'],
['-z'],
]
foreach args : bad_args
name = ' '.join(args)
test(name, serdi,
args: args,
should_fail: true,
suite: ['serdi', 'options'])
endforeach
test('none', serdi, should_fail: true, suite: ['serdi', 'options'])
test('quiet', files('test_quiet.py'),
args: script_args + files('bad/bad-base.ttl'),
suite: ['serdi', 'options'])
# Inputs
test('stdin', files('test_stdin.py'),
args: script_args,
suite: ['serdi', 'input'])
test('string', serdi,
args: ['-s', '<foo> a <Bar> .'],
should_fail: true,
suite: ['serdi', 'input'])
test('missing', serdi,
args: ['-i', 'turtle'],
should_fail: true,
suite: ['serdi', 'input'])
test('no_such_file', serdi,
args: ['no_such_file'],
should_fail: true,
suite: ['serdi', 'input'])
test('remote', serdi,
args: ['ftp://example.org/unsupported.ttl'],
should_fail: true,
suite: ['serdi', 'input'])
# IO errors
test('read_dir', serdi,
args: ['-e', 'file://@0@/'.format(meson.source_root())],
should_fail: true,
suite: 'io_errors')
test('bulk_read_dir', serdi,
args: ['file://@0@/'.format(meson.source_root())],
should_fail: true,
suite: 'io_errors')
test('write_error', files('test_write_error.py'),
args: script_args + [serd_ttl],
suite: 'io_errors')
# RDF test suites
## Serd-specific test suites
serd_suites = ['good', 'bad', 'lax']
serd_base = 'http://drobilla.net/sw/serd/test/'
### Run all suites with no special arguments
foreach name : serd_suites
manifest = files(name / 'manifest.ttl')
base_uri = serd_base + name + '/'
test(name, run_test_suite,
args: script_args + [manifest, base_uri],
suite: ['rdf', 'serd'],
timeout: 240)
endforeach
### Run the lax suite with lax parsing enabled as well
manifest = files('lax/manifest.ttl')
base_uri = serd_base + 'lax/'
test('lax', run_test_suite,
args: script_args + [manifest, base_uri, '--', '-l'],
suite: ['rdf', 'serd'],
timeout: 240)
## Standard W3C test suites
w3c_suites = ['Turtle', 'NTriples', 'NQuads', 'TriG']
w3c_base = 'http://www.w3.org/2013/'
foreach syntax : w3c_suites
manifest = files(syntax + 'Tests' / 'manifest.ttl')
base_uri = w3c_base + syntax + 'Tests/'
args = ['--syntax', syntax, manifest, base_uri]
if syntax == 'TriG'
args += ['--', '-a']
endif
test(syntax, run_test_suite,
args: script_args + args,
suite: ['rdf', 'w3c'],
timeout: 240)
endforeach
endif

21
test/test_quiet.py

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
#!/usr/bin/env python3
"""Test serdi quiet option."""
import argparse
import sys
import shlex
import subprocess
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--serdi", default="./serdi", help="path to serdi")
parser.add_argument("--wrapper", default="", help="executable wrapper")
parser.add_argument("input", help="invalid input file")
args = parser.parse_args(sys.argv[1:])
command = shlex.split(args.wrapper) + [args.serdi, "-q", args.input]
proc = subprocess.run(command, check=False, capture_output=True)
assert proc.returncode != 0
assert len(proc.stderr) == 0

38
test/test_stdin.py

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""Test reading from stdin with serdi."""
import argparse
import sys
import shlex
import subprocess
import tempfile
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--serdi", default="./serdi", help="path to serdi")
parser.add_argument("--wrapper", default="", help="executable wrapper")
args = parser.parse_args(sys.argv[1:])
command = shlex.split(args.wrapper) + [args.serdi, "-"]
DOCUMENT = "<{0}s> <{0}p> <{0}o> .".format("http://example.org/")
with tempfile.TemporaryFile() as out:
proc = subprocess.run(
command,
check=False,
encoding="utf-8",
input=DOCUMENT,
stdout=out,
stderr=subprocess.PIPE,
)
assert proc.returncode == 0
assert len(proc.stderr) == 0
out.seek(0)
lines = out.readlines()
assert len(lines) == 1
assert lines[0].decode("utf-8").strip() == DOCUMENT

31
test/test_write_error.py

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
#!/usr/bin/env python3
"""Test errors writing to a file."""
import argparse
import sys
import shlex
import subprocess
import os
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--serdi", default="./serdi", help="path to serdi")
parser.add_argument("--wrapper", default="", help="executable wrapper")
parser.add_argument("input", help="valid input file")
args = parser.parse_args(sys.argv[1:])
command = shlex.split(args.wrapper) + [args.serdi, args.input]
if os.path.exists("/dev/full"):
with open("/dev/full", "w") as out:
proc = subprocess.run(
command, check=False, stdout=out, stderr=subprocess.PIPE
)
assert proc.returncode != 0
assert "error" in proc.stderr.decode("utf-8")
else:
sys.stderr.write("warning: /dev/full not present, skipping test")

27
waf vendored

@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
#!/usr/bin/env python
# Minimal waf script for projects that include waflib directly
import sys
import inspect
import os
try:
from waflib import Context, Scripting
except Exception as e:
sys.stderr.write('error: Failed to import waf (%s)\n' % e)
if os.path.exists('.git'):
sys.stderr.write("Are submodules up to date? "
"Try 'git submodule update --init --recursive'\n")
sys.exit(1)
def main():
script_path = os.path.abspath(inspect.getfile(inspect.getmodule(main)))
project_path = os.path.dirname(script_path)
Scripting.waf_entry_point(os.getcwd(), Context.WAFVERSION, project_path)
if __name__ == '__main__':
main()

1
waflib

@ -1 +0,0 @@ @@ -1 +0,0 @@
Subproject commit b600c928b221a001faeab7bd92786d0b25714bc8

506
wscript

@ -1,506 +0,0 @@ @@ -1,506 +0,0 @@
#!/usr/bin/env python
import glob
import os
import sys
from waflib import Build, Logs, Options
from waflib.extras import autowaf
# Library and package version (UNIX style major, minor, micro)
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
SERD_VERSION = '0.30.9'
SERD_MAJOR_VERSION = '0'
# Mandatory waf variables
APPNAME = 'serd' # Package name for waf dist
VERSION = SERD_VERSION # Package version for waf dist
top = '.' # Source directory
out = 'build' # Build directory
# Release variables
uri = 'http://drobilla.net/sw/serd'
dist_pattern = 'http://download.drobilla.net/serd-%d.%d.%d.tar.bz2'
post_tags = ['Hacking', 'RDF', 'Serd']
def options(ctx):
ctx.load('compiler_c')
ctx.add_flags(
ctx.configuration_options(),
{'no-utils': 'do not build command line utilities',
'stack-check': 'include runtime stack sanity checks',
'static': 'build static library',
'no-shared': 'do not build shared library',
'static-progs': 'build programs as static binaries',
'largefile': 'build with large file support on 32-bit systems',
'no-posix': 'do not use POSIX functions, even if present'})
def configure(conf):
conf.load('compiler_c', cache=True)
conf.load('autowaf', cache=True)
if conf.env.DOCS:
conf.load('sphinx')
if not autowaf.set_c_lang(conf, 'c11', mandatory=False):
autowaf.set_c_lang(conf, 'c99')
if Options.options.strict:
# Check for programs used by lint target
conf.find_program("flake8", var="FLAKE8", mandatory=False)
conf.find_program("clang-tidy", var="CLANG_TIDY", mandatory=False)
conf.find_program("iwyu_tool", var="IWYU_TOOL", mandatory=False)
if Options.options.ultra_strict:
autowaf.add_compiler_flags(conf.env, '*', {
'clang': [
'-Wno-cast-align',
'-Wno-cast-qual',
'-Wno-conversion',
'-Wno-covered-switch-default',
'-Wno-disabled-macro-expansion',
'-Wno-double-promotion',
'-Wno-format-nonliteral',
'-Wno-implicit-fallthrough',
'-Wno-nullability-extension',
'-Wno-nullable-to-nonnull-conversion',
'-Wno-padded',
'-Wno-reserved-id-macro',
'-Wno-sign-conversion',
],
'gcc': [
'-Wno-cast-align',
'-Wno-cast-qual',
'-Wno-float-conversion',
'-Wno-inline',
'-Wno-padded',
'-Wno-sign-conversion',
],
'msvc': [
'/wd4061', # enumerator in switch is not explicitly handled
'/wd4365', # signed/unsigned mismatch
'/wd4514', # unreferenced inline function has been removed
'/wd4710', # function not inlined
'/wd4711', # function selected for automatic inline expansion
'/wd4820', # padding added after construct
'/wd4996', # POSIX name for this item is deprecated
],
})
autowaf.add_compiler_flags(conf.env, 'c', {
'clang': [
'-Wno-bad-function-cast',
],
'gcc': [
'-Wno-bad-function-cast',
],
'msvc': [
'/wd4706', # assignment within conditional expression
'/wd5045', # will insert Spectre mitigation for memory load
],
})
if 'mingw' in conf.env.CC[0]:
conf.env.append_value('CFLAGS', '-Wno-unused-macros')
conf.env.update({
'BUILD_UTILS': not Options.options.no_utils,
'BUILD_SHARED': not Options.options.no_shared,
'STATIC_PROGS': Options.options.static_progs,
'BUILD_STATIC': (Options.options.static or
Options.options.static_progs)})
if not conf.env.BUILD_SHARED and not conf.env.BUILD_STATIC:
conf.fatal('Neither a shared nor a static build requested')
if Options.options.stack_check:
conf.define('SERD_STACK_CHECK', SERD_VERSION)
if Options.options.largefile:
conf.env.append_unique('DEFINES', ['_FILE_OFFSET_BITS=64'])
conf.check_function('c', 'aligned_alloc',
header_name = 'stdlib.h',
return_type = 'void*',
arg_types = 'size_t,size_t',
define_name = 'HAVE_ALIGNED_ALLOC',
mandatory = False)
if not Options.options.no_posix:
funcs = {'posix_memalign': ('stdlib.h', 'int', 'void**,size_t,size_t'),
'posix_fadvise': ('fcntl.h', 'int', 'int,off_t,off_t,int'),
'fileno': ('stdio.h', 'int', 'FILE*')}
for name, (header, ret, args) in funcs.items():
conf.check_function('c', name,
header_name = header,
return_type = ret,
arg_types = args,
define_name = 'HAVE_' + name.upper(),
defines = ['_POSIX_C_SOURCE=200809L'],
mandatory = False)
# Set up environment for building/using as a subproject
autowaf.set_lib_env(conf, 'serd', SERD_VERSION,
include_path=str(conf.path.find_node('include')))
if conf.env.BUILD_TESTS:
serdi_node = conf.path.get_bld().make_node('serdi_static')
else:
serdi_node = conf.path.get_bld().make_node('serdi')
conf.env.SERDI = [serdi_node.abspath()]
conf.define('SERD_NO_DEFAULT_CONFIG', 1)
autowaf.display_summary(
conf,
{'Build static library': bool(conf.env['BUILD_STATIC']),
'Build shared library': bool(conf.env['BUILD_SHARED']),
'Build utilities': bool(conf.env['BUILD_UTILS']),
'Build unit tests': bool(conf.env['BUILD_TESTS'])})
lib_headers = ['src/reader.h']
lib_source = ['src/base64.c',
'src/byte_source.c',
'src/env.c',
'src/n3.c',
'src/node.c',
'src/reader.c',
'src/string.c',
'src/system.c',
'src/uri.c',
'src/writer.c']
def build(bld):
# C Headers
includedir = '${INCLUDEDIR}/serd-%s/serd' % SERD_MAJOR_VERSION
bld.install_files(includedir, bld.path.ant_glob('include/serd/*.h'))
# Pkgconfig file
autowaf.build_pc(bld, 'SERD', SERD_VERSION, SERD_MAJOR_VERSION, [],
{'SERD_MAJOR_VERSION': SERD_MAJOR_VERSION})
defines = []
lib_args = {'export_includes': ['include'],
'includes': ['include'],
'cflags': ['-fvisibility=hidden'],
'lib': ['m'],
'vnum': SERD_VERSION,
'install_path': '${LIBDIR}'}
if bld.env.MSVC_COMPILER:
lib_args['cflags'] = []
lib_args['lib'] = []
defines = []
# Shared Library
if bld.env.BUILD_SHARED:
bld(features = 'c cshlib',
source = lib_source,
name = 'libserd',
target = 'serd-%s' % SERD_MAJOR_VERSION,
defines = defines + ['SERD_INTERNAL'],
**lib_args)
# Static library
if bld.env.BUILD_STATIC:
bld(features = 'c cstlib',
source = lib_source,
name = 'libserd_static',
target = 'serd-%s' % SERD_MAJOR_VERSION,
defines = defines + ['SERD_STATIC', 'SERD_INTERNAL'],
**lib_args)
if bld.env.BUILD_TESTS:
coverage_flags = [''] if bld.env.NO_COVERAGE else ['--coverage']
test_args = {'includes': ['include'],
'cflags': coverage_flags,
'linkflags': coverage_flags,
'lib': lib_args['lib'],
'install_path': ''}
# Profiled static library for test coverage
bld(features = 'c cstlib',
source = lib_source,
name = 'libserd_profiled',
target = 'serd_profiled',
defines = defines + ['SERD_STATIC', 'SERD_INTERNAL'],
**test_args)
# Test programs
for prog in [('serdi_static', 'src/serdi.c'),
('test_env', 'test/test_env.c'),
('test_free_null', 'test/test_free_null.c'),
('test_node', 'test/test_node.c'),
('test_read_chunk', 'test/test_read_chunk.c'),
('test_reader_writer', 'test/test_reader_writer.c'),
('test_string', 'test/test_string.c'),
('test_uri', 'test/test_uri.c')]:
bld(features = 'c cprogram',
source = prog[1],
use = 'libserd_profiled',
target = prog[0],
defines = defines + ['SERD_STATIC'],
**test_args)
# Utilities
if bld.env.BUILD_UTILS:
obj = bld(features = 'c cprogram',
source = 'src/serdi.c',
target = 'serdi',
includes = ['include'],
use = 'libserd',
lib = lib_args['lib'],
install_path = '${BINDIR}')
if not bld.env.BUILD_SHARED or bld.env.STATIC_PROGS:
obj.use = 'libserd_static'
if bld.env.STATIC_PROGS:
obj.env.SHLIB_MARKER = obj.env.STLIB_MARKER
obj.linkflags = ['-static']
# Documentation
if bld.env.DOCS:
bld.recurse('doc/c')
# Man page
bld.install_files('${MANDIR}/man1', 'doc/serdi.1')
bld.add_post_fun(autowaf.run_ldconfig)
class LintContext(Build.BuildContext):
fun = cmd = 'lint'
def lint(ctx):
"checks code for style issues"
import subprocess
st = 0
if "FLAKE8" in ctx.env:
Logs.info("Running flake8")
st = subprocess.call([ctx.env.FLAKE8[0],
"wscript",
"--ignore",
"E101,E129,W191,E221,W504,E251,E241,E741"])
st += subprocess.call([ctx.env.FLAKE8[0],
"scripts/serd_bench.py",
"--ignore",
"E203"])
else:
Logs.warn("Not running flake8")
if "IWYU_TOOL" in ctx.env:
Logs.info("Running include-what-you-use")
cmd = [ctx.env.IWYU_TOOL[0], "-o", "clang", "-p", "build"]
output = subprocess.check_output(cmd).decode('utf-8')
if 'error: ' in output:
sys.stdout.write(output)
st += 1
else:
Logs.warn("Not running include-what-you-use")
if "CLANG_TIDY" in ctx.env and "clang" in ctx.env.CC[0]:
Logs.info("Running clang-tidy")
sources = glob.glob('include/serd/*.h*')
sources += glob.glob('src/*.c')
sources += glob.glob('test/*.c')
sources = list(map(os.path.abspath, sources))
procs = []
for source in sources:
cmd = [ctx.env.CLANG_TIDY[0], "--quiet", "-p=.", source]
procs += [subprocess.Popen(cmd, cwd="build")]
for proc in procs:
stdout, stderr = proc.communicate()
st += proc.returncode
else:
Logs.warn("Not running clang-tidy")
if st != 0:
sys.exit(st)
def amalgamate(ctx):
"builds single-file amalgamated source"
import shutil
import re
shutil.copy('serd/serd.h', 'build/serd.h')
def include_line(line):
return (not re.match(r'#include "[^/]*\.h"', line) and
not re.match('#include "serd/serd.h"', line))
with open('build/serd.c', 'w') as amalgamation:
amalgamation.write('/* This is amalgamated code, do not edit! */\n')
amalgamation.write('#include "serd.h"\n\n')
for header_path in ['src/serd_internal.h',
'src/system.h',
'src/byte_sink.h',
'src/byte_source.h',
'src/stack.h',
'src/string_utils.h',
'src/uri_utils.h',
'src/reader.h']:
with open(header_path) as header:
for l in header:
if include_line(l):
amalgamation.write(l)
for f in lib_headers + lib_source:
with open(f) as fd:
amalgamation.write('\n/**\n @file %s\n*/' % f)
for l in fd:
if include_line(l):
amalgamation.write(l)
for i in ['c', 'h']:
Logs.info('Wrote build/serd.%s' % i)
def test(tst):
import tempfile
# Create test output directories
for i in ['bad', 'good', 'lax',
'TurtleTests', 'NTriplesTests', 'NQuadsTests', 'TriGTests']:
try: