make/tests/scripts/features/loadapi
Paul Smith 8e0e6c678f Remove the "preview" status from the loaded object feature
Add an ABI version both to the header file and passed to the setup
function.  Unfortunately this itself is an ABI break and I couldn't
find a good way to avoid it.

* NEWS: Announce the ABI is not a preview and the incompatibility.
* doc/make.texi: Remove the preview warnings for object loading.
Document the new ABI version argument.
* src/gnumake.h (GMK_ABI_VERSION): Set the ABI version to 1.
Add comments documenting the format of the setup function.
* src/load.c (setup_func_t): Rename from load_func_t.
(load_file): Pass the ABI version to the setup function.
* tests/scripts/features/load: Rework the setup function.
* tests/scripts/features/loadapi: Ditto.
2023-05-07 16:51:06 -04:00

228 lines
5.3 KiB
Perl

# -*-perl-*-
$description = "Test the shared object load API.";
$details = "Verify the different aspects of the shared object API.";
# Don't do anything if this system doesn't support "load"
exists $FEATURES{load} or return -1;
my $cc = get_config('CC');
if (! $cc) {
$verbose and print "Skipping load test: no CC defined\n";
return -1;
}
# First build a shared object
# Provide both a default and non-default load symbol
unlink(qw(testapi.c testapi.so));
open(my $F, '> testapi.c') or die "open: testapi.c: $!\n";
print $F <<'EOF' ;
#include <string.h>
#include <stdio.h>
#include "gnumake.h"
char *getenv (const char*);
int plugin_is_GPL_compatible;
int testapi_gmk_setup (unsigned int abi, const gmk_floc *floc);
static char *
test_eval (const char *buf)
{
gmk_eval (buf, 0);
return NULL;
}
static char *
test_expand (const char *val)
{
return gmk_expand (val);
}
static char *
test_noexpand (const char *val)
{
char *str = gmk_alloc (strlen (val) + 1);
strcpy (str, val);
return str;
}
static char *
func_test (const char *funcname, unsigned int argc, char **argv)
{
char *mem;
if (strcmp (funcname, "test-expand") == 0)
return test_expand (argv[0]);
if (strcmp (funcname, "test-eval") == 0)
return test_eval (argv[0]);
if (strcmp (funcname, "test-noexpand") == 0)
return test_noexpand (argv[0]);
mem = gmk_alloc (sizeof ("unknown"));
strcpy (mem, "unknown");
return mem;
}
int
testapi_gmk_setup (unsigned int abi, const gmk_floc *floc)
{
const char *verbose = getenv ("TESTAPI_VERBOSE");
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 (verbose)
{
printf ("testapi_gmk_setup\n");
if (verbose[0] == '2')
printf ("%s:%lu\n", floc->filenm, floc->lineno);
}
if (getenv ("TESTAPI_KEEP"))
return -1;
return 1;
}
EOF
close($F) or die "close: testapi.c: $!\n";
# Make sure we can compile
my $cflags = get_config('CFLAGS');
my $cppflags = get_config('CPPFLAGS');
my $ldflags = get_config('LDFLAGS');
my $sobuild = "$cc ".($srcdir? "-I$srcdir/src":'')." $cppflags $cflags -shared -fPIC $ldflags -o testapi.so testapi.c";
my $clog = `$sobuild 2>&1`;
if ($? != 0) {
$verbose and print "Failed to build testapi.so:\n$sobuild\n$_";
return -1;
}
# TEST 1
# Check the gmk_expand() function
run_make_test(q!
EXPAND = expansion
all: ; @echo $(test-expand $$(EXPAND))
load testapi.so
!,
'', "expansion\n");
# TEST 2
# Check the eval operation. Prove that the argument is expanded only once
run_make_test(q!
load testapi.so
TEST = bye
ASSIGN = VAR = $(TEST) $(shell echo there)
$(test-eval $(value ASSIGN))
TEST = hi
all:;@echo '$(VAR)'
!,
'', "hi there\n");
# TEST 2
# Check the no-expand capability
run_make_test(q!
load testapi.so
TEST = hi
all:;@echo '$(test-noexpand $(TEST))'
!,
'', "\$(TEST)\n");
# During all subsequent tests testapi.so exists.
#
my @loads = ('', q!
load testapi.so
load testapi.so
-load testapi.so
-load testapi.so
$(eval load testapi.so)
$(eval -load testapi.so)
!);
for my $extra_loads (@loads) {
my $n = 5;
if ($extra_loads) {
$n = 12;
}
# sv 63045.
# Test that having unloaded a shared object make loads it again, even if the
# shared object is not updated.
$ENV{TESTAPI_VERBOSE} = 1;
run_make_test("
load testapi.so
$extra_loads
all:; \$(info \$(test-expand hello))
testapi.so: force; \$(info \$@)
force:;
.PHONY: force
", '', "testapi_gmk_setup\ntestapi.so\ntestapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\n");
# sv 63045.
# Same as above, but testapi_gmk_setup returned -1.
$ENV{TESTAPI_KEEP} = 1;
$ENV{TESTAPI_VERBOSE} = 1;
run_make_test("
load testapi.so
$extra_loads
all:; \$(info \$(test-expand hello))
testapi.so: force; \$(info \$@)
force:;
.PHONY: force
", '', "testapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\n");
# sv 63045.
# Test that make exits, unless make can successfully update an unloaded shared
# object.
$ENV{TESTAPI_VERBOSE} = 1;
run_make_test("
load testapi.so
$extra_loads
all:; \$(info \$(test-expand hello))
testapi.so: force; @#HELPER# fail 1
force:;
.PHONY: force
", '', "testapi_gmk_setup\nfail 1\n#MAKE#: *** [#MAKEFILE#:$n: testapi.so] Error 1\n", 512);
# sv 63045.
# Same as above, but testapi_gmk_setup returned -1.
$ENV{TESTAPI_KEEP} = 1;
$ENV{TESTAPI_VERBOSE} = 1;
run_make_test("
load testapi.so
$extra_loads
all:; \$(info \$(test-expand hello))
testapi.so: force; @#HELPER# fail 1
force:;
.PHONY: force
", '', "testapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\n");
# sv 63100.
# Test that make supplies the correct floc when the shared object is loaded
# again.
$ENV{TESTAPI_VERBOSE} = 2;
run_make_test("
load testapi.so
$extra_loads
all:; \$(info \$(test-expand hello))
testapi.so: force; \$(info \$@)
force:;
.PHONY: force
", '', "testapi_gmk_setup\n#MAKEFILE#:2\ntestapi.so\ntestapi_gmk_setup\n#MAKEFILE#:2\nhello\n#MAKE#: 'all' is up to date.\n");
}
unlink(qw(testapi.c testapi.so)) unless $keep;
# This tells the test driver that the perl test script executed properly.
1;