diff options
author | Paul Smith <psmith@gnu.org> | 2023-05-07 16:51:12 -0400 |
---|---|---|
committer | Paul Smith <psmith@gnu.org> | 2023-05-14 18:26:35 -0400 |
commit | 1748e6641419e8a48f830caad072ed5b298577af (patch) | |
tree | a0650a8ee54b5ec4020a5b1277bd70cd903d4ac2 /tests | |
parent | 8e0e6c678f3cf1199751e3b097745531ceed34ed (diff) | |
download | make-git-1748e6641419e8a48f830caad072ed5b298577af.tar.gz |
[SV 63219] Support an "unload" function for loaded objects
If a loaded object defines a symbol <object>_gmk_unload, assume it's
a function and invoke it whenever the loaded object is unloaded.
Original implementation by Dmitry Goncharov <dgoncharov@users.sf.net>
* NEWS: Announce the change.
* doc/make.texi: Describe the behavior.
* src/gnumake.h: Add information to the comments.
* src/makeint.h (unload_all): Declare a new function.
* src/main.c (die): Invoke unload_all().
* src/load.c (unload_func_t): Declare a new type for unload.
(struct load_list): Remember the unload symbol if it exists.
(load_object): Move the parsing of the object name from load_file.
Check for the _gmk_unload symbol and if found, remember it.
(load_file): Allow load_object to do object filename parsing.
(unload_file): Remove the load_list entry when unloading the object.
(unload_all): Unload all the loaded objects.
* tests/scripts/features/loadapi: Test the unload function.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/scripts/features/loadapi | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/tests/scripts/features/loadapi b/tests/scripts/features/loadapi index 311260f9..50e5d05f 100644 --- a/tests/scripts/features/loadapi +++ b/tests/scripts/features/loadapi @@ -93,6 +93,32 @@ testapi_gmk_setup (unsigned int abi, const gmk_floc *floc) return 1; } + +int +alternative_setup () +{ + gmk_add_function ("test-expand", func_test, 1, 1, GMK_FUNC_DEFAULT); + gmk_add_function ("test-noexpand", func_test, 1, 1, GMK_FUNC_NOEXPAND); + gmk_add_function ("test-eval", func_test, 1, 1, GMK_FUNC_DEFAULT); + gmk_add_function ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.", func_test, 0, 0, 0); + + if (getenv ("TESTAPI_VERBOSE")) + printf ("alternative_setup\n"); + + if (getenv ("TESTAPI_KEEP")) + return -1; + + return 1; +} + +void +testapi_gmk_unload () +{ + const char *s = getenv ("TESTAPI_VERBOSE"); + if (s && *s == '3') + printf ("testapi_gmk_unload\n"); +} + EOF close($F) or die "close: testapi.c: $!\n"; @@ -222,7 +248,70 @@ force:; ", '', "testapi_gmk_setup\n#MAKEFILE#:2\ntestapi.so\ntestapi_gmk_setup\n#MAKEFILE#:2\nhello\n#MAKE#: 'all' is up to date.\n"); } +my @names = ('testapi.so', './testapi.so', '#PWD#/testapi.so'); + +for my $name (@names) { + +# Test the make correctly figures out the name of the close function and runs +# the close function. +$ENV{TESTAPI_VERBOSE} = 3; +run_make_test(" +load $name +all:; \$(info \$(test-expand hello)) +", '', "testapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\ntestapi_gmk_unload\n"); +} + +# Same as above, but the setup function is custom. +@names = ('testapi.so(alternative_setup)', './testapi.so(alternative_setup)', + '#PWD#/testapi.so(alternative_setup)'); +for my $name (@names) { + +# Test the close function. +$ENV{TESTAPI_VERBOSE} = 3; +run_make_test(" +load $name +all:; \$(info \$(test-expand hello)) +", '', "alternative_setup\nhello\n#MAKE#: 'all' is up to date.\ntestapi_gmk_unload\n"); +} + +# Test that makes runs the close function on failure. +$ENV{TESTAPI_VERBOSE} = 3; +run_make_test(q! +load testapi.so +all: bad_preqreq; : +!, '', "testapi_gmk_setup\n#MAKE#: *** No rule to make target 'bad_preqreq', needed by 'all'. Stop.\ntestapi_gmk_unload\n", 512); + +# Test that make unloads a shared object, calls the close function, loads +# the plugin again, and then calls the close function again on exit. +&utouch(-10, 'testapi.so'); +$ENV{TESTAPI_VERBOSE} = 3; +run_make_test(" +load testapi.so +all:; \$(info \$(test-expand hello)) +testapi.so: testapi.c; $sobuild +", '', "testapi_gmk_setup\ntestapi_gmk_unload\n$sobuild\ntestapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\ntestapi_gmk_unload"); + +# Test that make unloads a shared object, calls the close function, loads +# the plugin again, and then calls the close function again on exit. +$ENV{TESTAPI_VERBOSE} = 3; +run_make_test(q! +load testapi.so +all:; $(info $(test-expand hello)) +testapi.so: force; $(info $@) +force:; +.PHONY: force +!, '', "testapi_gmk_setup\ntestapi_gmk_unload\ntestapi.so\ntestapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\ntestapi_gmk_unload\n"); + unlink(qw(testapi.c testapi.so)) unless $keep; +# Test that make does not run the close function, unless the shared object +# loaded successfully. +unlink('testapi.so'); +$ENV{TESTAPI_VERBOSE} = 3; +run_make_test(q! +load testapi.so +all:; : +!, '', "#MAKEFILE#:2: testapi.so: cannot open shared object file: $ERR_no_such_file\n#MAKEFILE#:2: *** testapi.so: failed to load. Stop.\n", 512); + # This tells the test driver that the perl test script executed properly. 1; |