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

buildsys: link installed gap executable against libgap and set SYS_DEFAULT_PATHS #5193

Merged
merged 3 commits into from
Nov 14, 2022
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
46 changes: 22 additions & 24 deletions Makefile.rules
Original file line number Diff line number Diff line change
Expand Up @@ -300,13 +300,12 @@ ifneq (,$(findstring cygwin,$(host_os)))
else
ifneq (,$(findstring darwin,$(host_os)))
GAC_CFLAGS = -fno-common
# HACK: we need to point to the real GAP binary, not a shell script
# wrapper. We can remove this hack (and once again use SYSINFO_GAP)
# once we get rid of the shell script wrapper
GAC_LDFLAGS = -bundle -bundle_loader $(SYSINFO_GAP2)
GAC_LDFLAGS = -bundle -bundle_loader $(SYSINFO_GAP)
GAC_LDFLAGS_FOR_INSTALL = -bundle -L$(libdir) -lgap
else
GAC_CFLAGS = -fPIC
GAC_LDFLAGS = -shared
GAC_LDFLAGS = -shared -fPIC
GAC_LDFLAGS_FOR_INSTALL = -shared -fPIC -L$(libdir) -lgap
endif
endif

Expand All @@ -317,7 +316,6 @@ endif

# paths to gap and gac executable
SYSINFO_GAP = $(abs_builddir)/gap
SYSINFO_GAP2 = $(abs_builddir)/gap # HACK for bundle_loader support
SYSINFO_GAC = $(abs_builddir)/gac


Expand Down Expand Up @@ -473,10 +471,19 @@ gap$(EXEEXT): libgap.la cnf/GAP-LDFLAGS cnf/GAP-LIBS cnf/GAP-OBJS build/obj/src/

else

# Linking rule and dependencies for the main gap executable
# build rule for the main gap executable
gap$(EXEEXT): $(OBJS) cnf/GAP-LDFLAGS cnf/GAP-LIBS cnf/GAP-OBJS build/obj/src/main.c.lo
$(QUIET_LINK)$(LINK) $(GAP_LDFLAGS) build/obj/src/main.c.lo $(GAP_LIBS) $(OBJS) -o $@

# generate a modified copy of main.c for use by the `gap-install` binary
build/main.c: src/main.c
@echo "#define SYS_DEFAULT_PATHS \"$(libdir)/gap;$(datarootdir)/gap\"" > $@
@cat $< >> $@

# build rule for the gap executable used by the `install-bin` target
build/gap-install: libgap.la cnf/GAP-LDFLAGS cnf/GAP-LIBS cnf/GAP-OBJS build/obj/build/main.c.lo
$(QUIET_LINK)$(LINK) $(GAP_LDFLAGS) build/obj/build/main.c.lo $(GAP_LIBS) libgap.la -o $@

endif

########################################################################
Expand Down Expand Up @@ -572,23 +579,14 @@ install: install-bin install-doc install-gaproot install-sysinfo install-headers
@echo "| via support@gap-system.org or https://github.com/gap-system/gap/issues |"
@echo "+--------------------------------------------------------------------------+"

# the following is wrapper script which is installed by the install-bin target
define gap_wrapper
#!/bin/sh
exec "$(libdir)/gap/gap" -l "$(libdir)/gap;$(datarootdir)/gap" "$$@"
endef
export gap_wrapper

install-bin: gap
# install the real GAP executable as $(libdir)/gap/gap
$(INSTALL) -d -m 0755 $(DESTDIR)$(libdir)/gap
$(LTINSTALL) -s gap $(DESTDIR)$(libdir)/gap

# install a wrapper shell script invoking the real GAP executable as $(bindir)/gap
install-bin: build/gap-install
# install a special build of gap with SYS_DEFAULT_PATHS set suitably
$(INSTALL) -d -m 0755 $(DESTDIR)$(bindir)
echo "$$gap_wrapper" > $(DESTDIR)$(bindir)/gap
chmod 0755 $(DESTDIR)$(bindir)/gap

$(LTINSTALL) -s build/gap-install $(DESTDIR)$(bindir)/gap
# for backwards compatibility, also install it into $(libdir)/gap
$(INSTALL) -d -m 0755 $(DESTDIR)$(libdir)/gap
$(LTINSTALL) -s build/gap-install $(DESTDIR)$(libdir)/gap/gap
# install gac
sed -e "s;@SYSINFO_GAPROOT@;$(libdir)/gap;" < $(srcdir)/cnf/gac.in > $(DESTDIR)$(bindir)/gac
chmod 0755 $(DESTDIR)$(bindir)/gac

Expand Down Expand Up @@ -637,8 +635,8 @@ install-gaproot: CITATION
install-sysinfo: SYSINFO_CPPFLAGS = -I${includedir}/gap $(GAP_DEFINES)
install-sysinfo: SYSINFO_LDFLAGS = $(ABI_CFLAGS)
install-sysinfo: SYSINFO_GAP = $(bindir)/gap
install-sysinfo: SYSINFO_GAP2 = $(libdir)/gap/gap
install-sysinfo: SYSINFO_GAC = $(bindir)/gac
install-sysinfo: GAC_LDFLAGS = $(GAC_LDFLAGS_FOR_INSTALL)
install-sysinfo: GMP_PREFIX =
install-sysinfo:
$(INSTALL) -d -m 0755 $(DESTDIR)$(libdir)/gap
Expand Down
169 changes: 167 additions & 2 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,183 @@
*/

#include "common.h"
#include "sysfiles.h"
#include "sysroots.h"
#include "sysstr.h"
#include "system.h"

#ifdef HPCGAP
#include "hpc/thread.h"
#endif

#include "config.h"

extern int realmain(int argc, char *argv[]);
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
extern int realmain(int argc, char * argv[]);

/****************************************************************************
**
*F * * * * * * * * * * finding location of executable * * * * * * * * * * * *
*/

#ifdef SYS_DEFAULT_PATHS

static void SetupInitialGapRoot(const char * argv0)
{
SySetGapRootPath(SYS_DEFAULT_PATHS);
}

#else

/****************************************************************************
**
** The function 'find_yourself' is based on code (C) 2015 Mark Whitis, under
** the MIT License : https://stackoverflow.com/a/34271901/928031
*/
static void
find_yourself(const char * argv0, char * result, size_t resultsize)
{
GAP_ASSERT(resultsize >= GAP_PATH_MAX);

char tmpbuf[GAP_PATH_MAX];

// absolute path, like '/usr/bin/gap'
if (argv0[0] == '/') {
if (realpath(argv0, result) && !access(result, F_OK)) {
return; // success
}
}
// relative path, like 'bin/gap.sh'
else if (strchr(argv0, '/')) {
if (!getcwd(tmpbuf, sizeof(tmpbuf)))
return;
gap_strlcat(tmpbuf, "/", sizeof(tmpbuf));
gap_strlcat(tmpbuf, argv0, sizeof(tmpbuf));
if (realpath(tmpbuf, result) && !access(result, F_OK)) {
return; // success
}
}
// executable name, like 'gap'
else {
char pathenv[GAP_PATH_MAX], *saveptr, *pathitem;
gap_strlcpy(pathenv, getenv("PATH"), sizeof(pathenv));
pathitem = strtok_r(pathenv, ":", &saveptr);
for (; pathitem; pathitem = strtok_r(NULL, ":", &saveptr)) {
gap_strlcpy(tmpbuf, pathitem, sizeof(tmpbuf));
gap_strlcat(tmpbuf, "/", sizeof(tmpbuf));
gap_strlcat(tmpbuf, argv0, sizeof(tmpbuf));
if (realpath(tmpbuf, result) && !access(result, F_OK)) {
return; // success
}
}
}

*result = 0; // reset buffer after error
}

static void SetupGAPLocation(const char * argv0, char * GAPExecLocation)
{
// In the code below, we keep resetting locBuf, as some of the methods we
// try do not promise to leave the buffer empty on a failed return.
char locBuf[GAP_PATH_MAX] = "";
Int4 length = 0;

#if defined(__APPLE__) && defined(__MACH__)
uint32_t len = sizeof(locBuf);
if (_NSGetExecutablePath(locBuf, &len) != 0) {
*locBuf = 0; // reset buffer after error
}
#endif

// try Linux procfs
if (!*locBuf) {
ssize_t ret = readlink("/proc/self/exe", locBuf, sizeof(locBuf));
if (ret < 0)
*locBuf = 0; // reset buffer after error
}

// try FreeBSD / DragonFly BSD procfs
if (!*locBuf) {
ssize_t ret = readlink("/proc/curproc/file", locBuf, sizeof(locBuf));
if (ret < 0)
*locBuf = 0; // reset buffer after error
}

// try NetBSD procfs
if (!*locBuf) {
ssize_t ret = readlink("/proc/curproc/exe", locBuf, sizeof(locBuf));
if (ret < 0)
*locBuf = 0; // reset buffer after error
}

// if we are still failing, go and search the path
if (!*locBuf) {
find_yourself(argv0, locBuf, GAP_PATH_MAX);
}

// resolve symlinks (if present)
if (!realpath(locBuf, GAPExecLocation))
*GAPExecLocation = 0; // reset buffer after error

// now strip the executable name off
length = strlen(GAPExecLocation);
while (length > 0 && GAPExecLocation[length] != '/') {
GAPExecLocation[length] = 0;
length--;
}
}

/****************************************************************************
**
*F SySetInitialGapRootPaths( <string> ) . . . . . set the root directories
**
** Set up GAP's initial root paths, based on the location of the
** GAP executable.
*/
static void SySetInitialGapRootPaths(const char * GAPExecLocation)
{
if (GAPExecLocation[0] != 0) {
// GAPExecLocation might be a subdirectory of GAP root,
// so we will go and search for the true GAP root.
// We try stepping back up to two levels.
char pathbuf[GAP_PATH_MAX];
char initgbuf[GAP_PATH_MAX];
strxcpy(pathbuf, GAPExecLocation, sizeof(pathbuf));
for (Int i = 0; i < 3; ++i) {
strxcpy(initgbuf, pathbuf, sizeof(initgbuf));
strxcat(initgbuf, "lib/init.g", sizeof(initgbuf));

if (SyIsReadableFile(initgbuf) == 0) {
SySetGapRootPath(pathbuf);
// escape from loop
return;
}
// try up a directory level
strxcat(pathbuf, "../", sizeof(pathbuf));
}
}

// Set GAP root path to current directory, if we have no other
// idea, and for backwards compatibility.
// Note that GAPExecLocation must always end with a slash.
SySetGapRootPath("./");
}

static void SetupInitialGapRoot(const char * argv0)
{
char GAPExecLocation[GAP_PATH_MAX] = "";
SetupGAPLocation(argv0, GAPExecLocation);
SySetInitialGapRootPaths(GAPExecLocation);
}
#endif

int main(int argc, char * argv[])
{
InstallBacktraceHandlers();
SetupInitialGapRoot(argv[0]);

#ifdef HPCGAP
RunThreadedMain(realmain, argc, argv);
Expand Down
Loading