Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ jobs:
- name: Tests (buffers, streams, filter chains, .lzma, checks, errors, the constants, every function linked, header mixing)
run: mcpp test $TARGET

# The release profile compiles a function to a section of its own and the link
# collects the unreferenced ones. 5.8.3 passed every test in the dev profile on
# Windows and faulted here: the functions were reached through import slots the
# linker made, and collected.
- name: Tests, where the link collects unreferenced sections (the release profile)
run: mcpp test --profile release $TARGET

- name: Export audit (the headers as clang reads them on this host)
if: startsWith(matrix.toolchain, 'llvm')
run: python3 tools/generate.py --check
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ upstream's own test files with the same library.
## Getting started

```sh
mcpp new pack --template mcpplibs.mwrap.xz@5.8.3
mcpp new pack --template mcpplibs.mwrap.xz@5.8.3.1
cd pack
mcpp run
```
Expand All @@ -37,7 +37,7 @@ it, and prints the sizes and the checksum.

```toml
[dependencies]
"mcpplibs.mwrap.xz" = "5.8.3"
"mcpplibs.mwrap.xz" = "5.8.3.1"
```

```cpp
Expand Down
4 changes: 2 additions & 2 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ C++ 常量。每次 CI 都用同一份库解码上游自己的测试文件。
## 快速开始

```sh
mcpp new pack --template mcpplibs.mwrap.xz@5.8.3
mcpp new pack --template mcpplibs.mwrap.xz@5.8.3.1
cd pack
mcpp run
```
Expand All @@ -33,7 +33,7 @@ mcpp run

```toml
[dependencies]
"mcpplibs.mwrap.xz" = "5.8.3"
"mcpplibs.mwrap.xz" = "5.8.3.1"
```

```cpp
Expand Down
9 changes: 9 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,12 @@ values under other names and `#undef` the macros before naming the constants
The package depends on `compat.xz` 5.8.3, which builds liblzma from the release
sources with the target's toolchain. A program that imports the module links
that library; it does not look for a system liblzma.

The library is static, and the module reads `lzma.h` with `LZMA_API_STATIC`
defined (5.8.3.1). On Windows the header otherwise declares every function
imported from a DLL, and a unit that read it so calls through `__imp_lzma_*`.
A unit that includes `lzma.h` itself beside the module defines
`LZMA_API_STATIC` before it, or includes `<mwrap/xz/macros.hpp>` first, which
defines it. 5.8.3 did not: its tests passed in the dev profile, and a program
built in the release profile, where the link collects unreferenced sections,
faulted at its first call into the library on Windows.
6 changes: 6 additions & 0 deletions include/mwrap/xz/macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
#ifndef MWRAP_XZ_MACROS_HPP
#define MWRAP_XZ_MACROS_HPP

// The configuration the compat package compiles with: a unit that includes the
// upstream header itself shares it by including this header first.
#ifndef LZMA_API_STATIC
#define LZMA_API_STATIC
#endif

#ifndef LZMA_STREAM_INIT
#define LZMA_STREAM_INIT { nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, 0, 0, 0, 0, LZMA_RESERVED_ENUM, LZMA_RESERVED_ENUM }
#endif
Expand Down
2 changes: 1 addition & 1 deletion mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[package]
namespace = "mcpplibs.mwrap"
name = "xz"
version = "5.8.3"
version = "5.8.3.1"
description = "XZ Utils 5.8.3 liblzma C++ modules for mcpp (import mcpplibs.mwrap.xz;): .xz and .lzma streams, filters, blocks, indexes and checks over compat.xz, with the constants of lzma.h as C++ constants"
license = "Apache-2.0"
authors = ["mcpp-community"]
Expand Down
3 changes: 3 additions & 0 deletions src/macros.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// the macro where the module is built (a named module cannot export a macro). The
// other macros are in <mwrap/xz/macros.hpp>. Written by tools/generate.py.
module;
#ifndef LZMA_API_STATIC
#define LZMA_API_STATIC
#endif
#include <lzma.h>

// The values, taken under other names while the macros are defined.
Expand Down
3 changes: 3 additions & 0 deletions src/xz.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// upstream declares it; the root also re-exports the macro mapping. The implementation
// is compat.xz 5.8.3. Written by tools/generate.py from the headers.
module;
#ifndef LZMA_API_STATIC
#define LZMA_API_STATIC
#endif
#include <lzma.h>

export module mcpplibs.mwrap.xz;
Expand Down
6 changes: 6 additions & 0 deletions tests/header_mix_test.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
// The header and the module in one translation unit: the same entities, so a
// stream set up through one spelling is ended through the other.
//
// A unit that includes the upstream header itself shares the configuration compat.xz
// is compiled with (<mwrap/xz/macros.hpp> states it too): the library is static.
#ifndef LZMA_API_STATIC
#define LZMA_API_STATIC
#endif
#include <lzma.h>
import std;
import mcpplibs.mwrap.xz;
Expand Down
15 changes: 13 additions & 2 deletions tests/linked.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@ int main()
};
int missing = 0;
for (const void* f : functions) missing += f == nullptr;
std::println("110 functions linked, {} null", missing);
return missing != 0;
// The functions are not at one address. A link that resolved them through slots it
// made for them and then dropped the functions leaves every slot the same address,
// which is not null. (Two functions of identical code may share one where the
// linker folds them, so only a run of more than half is read as that.)
std::vector<const void*> sorted(std::begin(functions), std::end(functions));
std::ranges::sort(sorted, std::less<const void*>{});
std::size_t run = 1, longest = 1;
for (std::size_t i = 1; i < sorted.size(); ++i) {
run = sorted[i] == sorted[i - 1] ? run + 1 : 1;
longest = std::max(longest, run);
}
std::println("110 functions linked, {} null, at most {} at one address", missing, longest);
return missing != 0 || longest > sorted.size() / 2;
}
3 changes: 3 additions & 0 deletions tests/macros.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// expands even in a qualified name, so the values of the headers are taken under other
// names and the macros undefined before the mapped names are used. Written by
// tools/generate.py.
#ifndef LZMA_API_STATIC
#define LZMA_API_STATIC
#endif
#include <lzma.h>

namespace header {
Expand Down
19 changes: 17 additions & 2 deletions tools/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ def render(cfg, surface, constants, types, kept):
'// The upstream header included after this one redefines these macros.',
'// Written by tools/generate.py.',
f'#ifndef {guard}', f'#define {guard}']
if cfg.get('defines'):
header += ['', '// The configuration the compat package compiles with: a unit that includes the',
'// upstream header itself shares it by including this header first.']
header += [f'#ifndef {d}\n#define {d}\n#endif' for d in cfg['defines']]
for n in sorted(kept):
# A module-only unit has no NULL macro; in C++ nullptr is its meaning.
body = re.sub(r'\bNULL\b', 'nullptr', qualify(kept[n]['body'], set(mapped), f'{scope}::macros'))
Expand Down Expand Up @@ -165,8 +169,19 @@ def render(cfg, surface, constants, types, kept):
' const void* volatile functions[] = {']
linked += [f' reinterpret_cast<const void*>(&{n}),' for n in functions]
linked += [' };', ' int missing = 0;', ' for (const void* f : functions) missing += f == nullptr;',
f' std::println("{len(functions)} functions linked, {{}} null", missing);',
' return missing != 0;', '}']
' // The functions are not at one address. A link that resolved them through slots it',
' // made for them and then dropped the functions leaves every slot the same address,',
' // which is not null. (Two functions of identical code may share one where the',
' // linker folds them, so only a run of more than half is read as that.)',
' std::vector<const void*> sorted(std::begin(functions), std::end(functions));',
' std::ranges::sort(sorted, std::less<const void*>{});',
' std::size_t run = 1, longest = 1;',
' for (std::size_t i = 1; i < sorted.size(); ++i) {',
' run = sorted[i] == sorted[i - 1] ? run + 1 : 1;',
' longest = std::max(longest, run);',
' }',
f' std::println("{len(functions)} functions linked, {{}} null, at most {{}} at one address", missing, longest);',
' return missing != 0 || longest > sorted.size() / 2;', '}']
join = lambda lines: '\n'.join(lines) + '\n'
return {f'src/{name}.cppm': join(module), 'src/macros.cppm': join(macros),
f'include/mwrap/{name}/macros.hpp': join(header), 'tests/macros.cpp': join(test),
Expand Down
7 changes: 7 additions & 0 deletions tools/surface.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ version = "5.8.3"
license = "0BSD"
generated-on = "linux"
headers = ["lzma.h"]
# compat.xz is a static library. On Windows lzma.h declares every function imported
# from a DLL unless this is defined (LZMA_API_IMPORT): a unit that read it so calls
# through `__imp_lzma_*`, which no DLL provides. lld-link then makes a slot of its own
# for each and does not count the slot as a reference, so in a link that collects
# unreferenced sections (-ffunction-sections, the release profile) the functions are
# dropped and each slot holds the image's first byte: the call faults (5.8.3).
defines = ["LZMA_API_STATIC"]
owned = ["lzma.h", "lzma/base.h", "lzma/bcj.h", "lzma/block.h", "lzma/check.h", "lzma/container.h",
"lzma/delta.h", "lzma/filter.h", "lzma/hardware.h", "lzma/index.h", "lzma/index_hash.h",
"lzma/lzma12.h", "lzma/stream_flags.h", "lzma/version.h", "lzma/vli.h"]
Expand Down
Loading