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

Update Meson build to 1.9.4 #1139

Merged
merged 1 commit into from Oct 25, 2022
Merged

Update Meson build to 1.9.4 #1139

merged 1 commit into from Oct 25, 2022

Conversation

tristan957
Copy link
Contributor

@tristan957 tristan957 commented Aug 16, 2022

Specifically this adds support for the following options:

  • LZ4_ALIGN_TEST
  • LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION
  • LZ4_DISTANCE_MAX
  • LZ4_FAST_DEC_LOOP
  • LZ4_FORCE_SW_BITCOUNT
  • LZ4_FREESTANDING
  • LZ4_USER_MEMORY_FUNCTIONS
  • compiling ossfuzz targets
  • compiling more test targets
  • registering some tests

@Cyan4973 here are all the changes that are necessary to make the Meson build as featureful as the Makefile build. Please let me know if I have missed something. It would be nice to get a 1.9.5 release in the event this is merged so Meson users can get the benefits of the 1.9.4 release too. Thanks!

@tristan957
Copy link
Contributor Author

cc @eli-schwartz for a review

tristan957 referenced this pull request Aug 16, 2022
The meson build had gotten a little out of hand. It needed to be cleaned
up and have its errors fixed. This should enable lz4 to switch to Meson
at any time should the need ever arise.
@diizzyy
Copy link

diizzyy commented Aug 16, 2022

It would be nice if unit tests could be added back too

@tristan957
Copy link
Contributor Author

Where are the unit tests even defined in the Makefile build? I can't tell.

@diizzyy
Copy link

diizzyy commented Aug 16, 2022

@eli-schwartz
Copy link
Contributor

eli-schwartz commented Aug 16, 2022

make test -> root Makefile, defines:

lz4/Makefile

Lines 135 to 138 in cfd6ab3

.PHONY: test
test:
$(MAKE) -C $(TESTDIR) $@
$(MAKE) -C $(EXDIR) $@

This runs make -C tests/ test -> Makefile in the tests/ directory

lz4/tests/Makefile

Lines 184 to 185 in cfd6ab3

.PHONY: test
test: test-lz4 test-lz4c test-frametest test-fullbench test-fuzzer test-amalgamation listTest test-decompress-partial

@tristan957
Copy link
Contributor Author

tristan957 commented Aug 16, 2022

hmm ok. I'll look into adding this. Seems like there are no arguments for the tests? Or I guess those are targets and I need to go look. Got it.

@Cyan4973
Copy link
Member

Cyan4973 commented Aug 16, 2022

Having automated CI tests for meson is indeed important,
not only to test the current PR, but also to ensure the properties it provides remain preserved in the future,

but I don't think they should be made part of make test.
meson tests can and should be separated.
It's allowed to create a helper like make test-meson to trigger them, but that's an independent topic.
They can also be triggered through their own command script.

What then matters is to have these tests running in CI.
At the moment, we have that :
https://github.com/lz4/lz4/runs/7853055740?check_suite_focus=true

which is itself triggered by :
https://github.com/lz4/lz4/blob/v1.9.4/.github/workflows/ci.yml#L683

The meson test script can be improved or completed to test more capabilities.

@Cyan4973
Copy link
Member

Also : could you write a high-level description in this PR head post of the shortcomings fixed by this PR ?

For the time being, I've mostly noticed integration lz4file and availability of new Build Macros.

@tristan957
Copy link
Contributor Author

I will get to it. I wasn't going to add meson test to the Makefile. Just add the same tests from the Makefile into the Meson infrastructure.

@tristan957
Copy link
Contributor Author

I could not get the fullbench and fuzzer tests to actually run, so I disabled them. Here is what is currently run.

$ meson test -C build/ 
ninja: Entering directory `/home/tristan957/Projects/lz4/contrib/meson/build'
ninja: no work to do.
1/4 checkFrame                            OK               0.04s
2/4 decompress-partial-usingDict.c        OK               0.03s
3/4 decompress-partial.c                  OK               0.02s
4/4 datagen                               OK               0.04s


Ok:                 4   
Expected Fail:      0   
Fail:               0   
Unexpected Pass:    0   
Skipped:            0   
Timeout:            0

I could use help figuring out what other tests I could run. Reading makefiles is not my specialty.

@tristan957
Copy link
Contributor Author

I added meson testing to the CI

@tristan957 tristan957 changed the title Update Meson build build 1.9.4 Update Meson build to 1.9.4 Aug 17, 2022
@tristan957
Copy link
Contributor Author

The freestanding test fails in debugoptimized and release builds under Meson:

Program received signal SIGSEGV, Segmentation fault.
memset (n=<optimized out>, c=0, s=0x7ffffffbda48) at ../../../tests/freestanding.c:207
207             *p++ = (uint8_t) c;
(gdb) p s
$1 = (void *) 0x7ffffffbda48
(gdb) bt
#0  memset (n=<optimized out>, c=0, s=0x7ffffffbda48) at ../../../tests/freestanding.c:207
#1  LZ4_initStreamHC (size=262200, buffer=0x7ffffffbda48) at ../../../tests/../lib/lz4hc.c:1021
#2  LZ4_initStreamHC (size=262200, buffer=0x7ffffffbda48) at ../../../tests/../lib/lz4hc.c:1011
#3  LZ4_compress_HC_extStateHC (compressionLevel=9, dstCapacity=1048576, srcSize=256, dst=0x524000 <compressBuffer.1> "", 
    src=0x421020 <README_md.4> "LZ4 - Extremely fast compression\n", '=' <repeats 32 times>, "\n\nLZ4 is lossless compression algorithm,\nproviding compression speed > 500 MB/s per core,\nscalable with multi-cores CPU.\nIt features an"..., state=0x7ffffffbda48) at ../../../tests/../lib/lz4hc.c:953
#4  LZ4_compress_HC (
    src=src@entry=0x421020 <README_md.4> "LZ4 - Extremely fast compression\n", '=' <repeats 32 times>, "\n\nLZ4 is lossless compression algorithm,\nproviding compression speed > 500 MB/s per core,\nscalable with multi-cores CPU.\nIt features an"..., dst=dst@entry=0x524000 <compressBuffer.1> "", srcSize=srcSize@entry=256, dstCapacity=dstCapacity@entry=1048576, 
    compressionLevel=compressionLevel@entry=9) at ../../../tests/../lib/lz4hc.c:968
#5  0x000000000041e969 in test_lz4hc (srcSize=256, 
    srcData=0x421020 <README_md.4> "LZ4 - Extremely fast compression\n", '=' <repeats 32 times>, "\n\nLZ4 is lossless compression algorithm,\nproviding compression speed > 500 MB/s per core,\--Type <RET> for more, q to quit, c to continue without paging--c
nscalable with multi-cores CPU.\nIt features an"...) at ../../../tests/freestanding.c:93
#6  test () at ../../../tests/freestanding.c:150
#7  0x0000000000420589 in _start () at ../../../tests/freestanding.c:230
(gdb) up
#1  LZ4_initStreamHC (size=262200, buffer=0x7ffffffbda48) at ../../../tests/../lib/lz4hc.c:1021
1021          MEM_INIT(hcstate, 0, sizeof(*hcstate)); }
(gdb) p *hcstate 
value of type `LZ4HC_CCtx_internal' requires 262192 bytes, which is more than max-value-size

Seems like a potential stack overflow given the size of the struct. I don't really know how to debug this.

@tristan957
Copy link
Contributor Author

freestanding: freestanding.c
	$(CC) -ffreestanding -nostdlib $^ -o $@$(EXT)

Maybe the lack of $(FLAGS) here means something.

@tristan957
Copy link
Contributor Author

I disabled the test in -O > 1 which I think matches the Makefile's intent.

@eli-schwartz
Copy link
Contributor

You could also set override_options for that test.

@tristan957
Copy link
Contributor Author

You could also set override_options for that test.

Great point. I always forget this. I will update it tonight.

Other than that, without anyone giving advice on what extra tests can and should be run, this PR seems to be nearing completion.

I tried to get the tests working that use the argument -T90s, but the tests run for much longer than 90 seconds. I can't tell if I am missing something.

Also, as you can see I create some static libraries for non-standalone fuzzers. Should those be exported as dependencies for external fuzzing tools to consume? It wasn't entirely obvious to me.

@tristan957
Copy link
Contributor Author

@diizzyy what tests did you have in mind?

'sources': files(lz4_source_root / 'tests/freestanding.c'),
'c_args': ['-ffreestanding', '-Wno-unused-parameter', '-Wno-declaration-after-statement'],
'link_args': ['-nostdlib'],
'test': cc.get_id() in ['gcc', 'clang'] and get_option('optimization') not in ['2', '3']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this validation for the cc id is needed to detect whether you can build the executable at all... but "test" only determines whether after building it, it is defined as a test.

This either needs to be a "build" key, or pull it out of the dict and check the cc id, then append to exes +=

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm yea, didn't notice this. Will fix tonight.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would also be cool to get MSVC + meson testing here, athough the WrapDB will eventually test it after release.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the msvc equivalent of the c and link args here?

There is no msvc testing in the CI currently, unfortunately.

@diizzyy
Copy link

diizzyy commented Aug 17, 2022

@tristan957
The unit tests so the ones you're hacking on support for right now =)

@tristan957
Copy link
Contributor Author

I would not say having 4 tests is that good of coverage.

@diizzyy
Copy link

diizzyy commented Aug 17, 2022

True, but it's better than none. Of course, if we could get the same converage as using Makefiles working that would be great.

@tristan957
Copy link
Contributor Author

The problem is identifying the tests. It isn't easy.

@Cyan4973
Copy link
Member

Cyan4973 commented Aug 17, 2022

The minimum set of tests that a built lz4 binary should pass is make check.

make test goes much farther than that, and also build additional test tools and run them, but I don't think this extended scope makes sense if the goal is just to check a meson build system.

Though if you also want to generate and then test the liblz4 library, as opposed to the lz4 CLI alone, then indeed it's better to also build and run tests/fuzzer and tests/frametest.

More advanced tests, including sanitizers and emulated targets, are already run using other build systems, I believe it's unnecessary to also build and run them through meson specifically, as this wouldn't add much value.

@tristan957
Copy link
Contributor Author

Ok I got test-lz4-skippable going. @Cyan4973 I moved the test out of the Makefile and into a POSIX shell script. Let me know what you think. If you like it, that is how I will continue writing the rest of the tests.

The test script requires the LZ4 env var to be set where previously the Makefile used $(LZ4) for the lz4 executable. It isn't super clean, but it is the best I can do given the constraints of all this :(.

@tristan957
Copy link
Contributor Author

I am having to do some shenanigans to not have to bump the Meson version unfortunately.

SKIPFILE="goldenSamples/skip.bin"
FPREFIX="tmp-lsk"

"${LZ4}" -dc "$SKIPFILE"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this shell script depends on $LZ4 being defined,
a useful feature would be to start with a test checking if $LZ4 is defined
and output a human readable error if it's not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I was going to add that. Just became lazy :). I will get to it. Thanks.

@Cyan4973
Copy link
Member

@Cyan4973 I moved the test out of the Makefile and into a POSIX shell script. Let me know what you think.

I think it generally makes sense,

now the devil is in the details,
and what also matters is to keep the code base in a maintainable state.

With regards to the test you extracted, I only have a minor comment, and I think it's good to go.

The conversion method might be generic enough to be applied to other tests,
we'll just have to review each test conversion to be sure.

@t-mat
Copy link
Contributor

t-mat commented Aug 18, 2022

If we convert test commands in Makefile to shell scripts, adding set -xe at the beginning of the script would be nice.

-x : Print each line of the script before executing it.
-e : Exit the script if exit code of the command isn't `0`.

set -x will help future contributors to understand what causes specific errors in the test script. (Similar to make V=1)

See also: https://stackoverflow.com/a/52961676

@tristan957
Copy link
Contributor Author

Ok. I was definitely going to add -e, but since it is requested, I will also add -x. I'll also add trap statements to cleanup the temporary files.

@eli-schwartz
Copy link
Contributor

I would add set -x after the initial setup of variables, since those don't need to be verbosely printed. Only the test command invocations are needed.

@tristan957
Copy link
Contributor Author

Good point.

@tristan957
Copy link
Contributor Author

$ meson test -C build/
ninja: Entering directory `/home/tristan957/Projects/lz4/contrib/meson/build'
ninja: no work to do.
 1/13 checkFrame                             OK               0.03s
 2/13 decompress-partial-usingDict.c         OK               0.03s
 3/13 decompress-partial.c                   OK               0.02s
 4/13 datagen                                OK               0.07s
 5/13 freestanding                           OK               0.07s
 6/13 lz4-frame-concatenation                OK               0.10s
 7/13 lz4-multiple                           OK               0.22s
 8/13 lz4-skippable                          OK               0.11s
 9/13 lz4-sparse                             OK               0.42s
10/13 lz4-contentSize                        OK               0.93s
11/13 lz4-opt-parser                         OK               4.12s
12/13 lz4-fast-hugefile                      OK              59.28s
13/13 lz4hc-hugefile                         OK             117.45s


Ok:                 13  
Expected Fail:      0   
Fail:               0   
Unexpected Pass:    0   
Skipped:            0   
Timeout:            0

More progress

@tristan957
Copy link
Contributor Author

Is there any way to use test to see if a command failed or not. I thought test ! cmd might work, but that doesn't seem to be the case.

Also does Windows even has a POSIX shell available to run the tests?

@tristan957
Copy link
Contributor Author

My Makefile changes are obviously wrong. Could someone point out the issue and the correction? I presume it is related to the PATH=$(PATH) ./test-xxx.

@eli-schwartz
Copy link
Contributor

Is there any way to use test to see if a command failed or not. I thought test ! cmd might work, but that doesn't seem to be the case.

The test program is basically a multi-call binary that accepts string arguments and checks them for equality or whether there is a file by that name and maybe how its modification date compares to another file.

It doesn't let you "test" the exit status of a command, but that's okay, bash already has that.

  • test ! cmd invokes test with two string arguments (but no test mode, which is only valid for implicit -n and a single argument).
  • ! cmd runs cmd and inverts the return value so that if the command fails, the shell notes a success, or if the command succeeds, the shell notes a failure.
  • if ! cmd; then checks to see if the shell notes a success (because the command fails), and when success is noted via the inversion, runs the contents of the conditional.

It's a common mistake that people think test is needed, or worse, think that [[ .... ]] (an alias for the test program) is part of the grammar of if [[ cmd ]] instead of if cmd where [[/test happens to be a valid cmd.

Also does Windows even has a POSIX shell available to run the tests?

You can install one, and similarly you can install tools such as diff, cmp, ls, cat, rm...

You might need to check for their availability before running the tests, port to python, or include an additional Windows Batch version.

@tristan957
Copy link
Contributor Author

I wasn't aware of starting a command with !. I thought that was make syntax. Good to know. I'll amend some of the tests tomorrow.

@tristan957
Copy link
Contributor Author

test-lz4-basic is failing when converted to a meson test. Would appreciate help diagnosing. Is the test also broken in the Makefile build?

@t-mat
Copy link
Contributor

t-mat commented Sep 9, 2022

Is the test also broken in the Makefile build?

No, it works fine. For example, see the following log.
https://github.com/lz4/lz4/runs/8264024948?check_suite_focus=true#step:15:288

@tristan957
Copy link
Contributor Author

Somehow the two files differ only in the Meson build. Makes no sense to me

@t-mat
Copy link
Contributor

t-mat commented Sep 9, 2022

Makes no sense to me

I'd like to focus your first error in the log.

https://github.com/lz4/lz4/runs/8263325959?check_suite_focus=true#step:15:33

/bin/sh: 1: ./test-lz4-multiple: not found

(1) This error message means /bin/sh failed to find ./test-lz4-multiple. As you know it actually means tests/test-lz4-multiple.

(2) I also couldn't find tests/test-lz4-multiple

$ cd /path/to/lz4/pr/1139
$ ( cd tests && ls ./test-lz4-multiple )
ls: cannot access './test-lz4-multiple': No such file or directory

(3) But there's tests/test-lz4-multiple.sh

(4) Therefore, I think that invocation of ./test-lz4-multiple in the tests/Makefile should be replaced by ./test-lz4-multiple.sh

(5) You may find similar errors.

@tristan957
Copy link
Contributor Author

Yea I left off the .sh. I will come around to take a second look later today.

@diizzyy
Copy link

diizzyy commented Oct 17, 2022

@tristan957
Great work, any luck figuring out the missing pieces?

@tristan957
Copy link
Contributor Author

I just haven't gotten back to this in a bit. Just got back from vacation. Maybe this week...

@tristan957
Copy link
Contributor Author

@t-mat @Cyan4973 I think this PR is ready for review, and the CI seems to agree :)

@tristan957
Copy link
Contributor Author

ping @eli-schwartz too if you want to review

echo "from underground..." > ${FPREFIX}2
lz4 -dcfm ${FPREFIX}1 ${FPREFIX}2
echo "---- non-existing source (must fail cleanly) ----"
! lz4 file-does-not-exist
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a problem in the translation of negative tests from Makefile to sh.

In the Makefile, if a test is expected to fail, it can be written, like here ! test_should_fail.
If, in contrast with expectation, test_should_fail actually succeeds,
the ! will make it fail, and Makefile execution will stop immediately.

However, for sh script, I don't think it works the same way.
I believe that, if test_should_fail succeeds, the ! will not stop execution.
As a consequence, the next line will be executed,
and the final result of the script will be unaffected by the outcome of test_should_fail.

This is obviously not a correct translation of a negative test.

When a test is supposed to fail, there is a need to proceed differently for sh. One method is to use the properties of && instead.
The test then becomes something like :

test_should_fail && die "the test should have failed"

with die() being a sh function designed to immediately stop execution of the script with an error code (typically exit).

So I'm afraid there's a bit more work to do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate the explanation. ShellCheck was giving me a similar warning, but I didn't quite understand it. With your explanation, I do get it. Fixed in latest update.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth adding a ShellCheck GitHub Action to the CI. From what I can tell, all these shell scripts would pass, except for one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a Makefile, the contents of a rule are evaluated as a series of shell scripts, each one run in turn but only if the previous one succeeded. The contents of the rules can be faithfully transcribed into a *.sh file, which @tristan957 was trying to do, and running set -e, the "errexit" option, causes the same rules to apply -- namely, that any command which fails causes the script to abort with an error, immediately.

Well, sort of. Actually, set -e has some intriguing gotchas. Some things aren't eligible to trigger early "error-exit". One of those things is... ! cmd. Another is cmd && othercmd, as well as cmd || othercmd.

Some gotchas of set -e are discussed at https://mywiki.wooledge.org/BashFAQ/105

Now, in the case of Make, since each line is actually executed as a script, you don't need errexit, because any line that fails will return that error to Make anyway. But for a shell script, you need to force any line that fails to exit explicitly. And that isn't as simple as it initially appears.

So yeah, that's why ! cmdcaused a problem here. Not because there's a difference between a Makefile and a shell script, but because the Makefile is running many small shell scripts, and the actual "real" shell script is just a single shell script.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a Makefile, the contents of a rule are evaluated as a series of shell scripts

This is good to know

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth adding a ShellCheck GitHub Action to the CI. From what I can tell, all these shell scripts would pass, except for one.

That's a good idea

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could add a follow up PR after this one merges, assuming it will.

Specifically this adds support for the following options:

- LZ4_ALIGN_TEST
- LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION
- LZ4_DISTANCE_MAX
- LZ4_FAST_DEC_LOOP
- LZ4_FORCE_SW_BITCOUNT
- LZ4_FREESTANDING
- LZ4_USER_MEMORY_FUNCTIONS
- compiling ossfuzz targets
- compiling more test targets
- registering some tests
@tristan957
Copy link
Contributor Author

tristan957 commented Oct 25, 2022

@Cyan4973 this is good to go. @eli-schwartz seems good to go with this as-is. A point release might also be nice, so Meson users can consume all the 1.9.4 goodies.

@eli-schwartz
Copy link
Contributor

I haven't taken a super close look at the latest version of this patch, but from a cursory inspection it seems good.

The fact that the tests now run the same way in both Make and meson is convenient, and very maintainable.

@Cyan4973 Cyan4973 merged commit 214bfb3 into lz4:dev Oct 25, 2022
tristan957 added a commit to hse-project/hse that referenced this pull request Nov 2, 2022
This takes advantage of a new upstream lz4 build system that I wrote in
lz4/lz4#1139. Unfortunately I have to wait until
1.9.5 to see the fruits of my labor in Meson's WrapDB.

Signed-off-by: Tristan Partin <tpartin@micron.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants