Merge remote-tracking branch 'lp-make/rpath-origin' into 7.0
* lp-make/rpath-origin: makeRPath allow multiple root directories redo softIoc to be more c++y rpath $ORIGIN doc older binutils compat travis-ci test rpath $ORIGIN epicsGetExecName WIN32, Darwin, solaris, freebsd epicsGetExecDir() paths relative to executable LINKER_USE_RPATH=ORIGIN # Conflicts: # configure/os/CONFIG.Common.linuxCommon
This commit is contained in:
@ -15,7 +15,7 @@ addons:
|
||||
script:
|
||||
- .ci/travis-build.sh
|
||||
env:
|
||||
- CMPLR=gcc
|
||||
- CMPLR=gcc EXTRA=LINKER_USE_RPATH=ORIGIN
|
||||
- CMPLR=clang
|
||||
- CMPLR=gcc STATIC=YES
|
||||
- CMPLR=clang STATIC=YES
|
||||
|
@ -45,6 +45,8 @@ FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
|
||||
TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl
|
||||
GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG) $(QUESTION_FLAG)
|
||||
|
||||
MAKERPATH = $(PYTHON) $(TOOLS)/makeRPath.py
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# tools for installing libraries and products
|
||||
INSTALL = $(PERL) $(TOOLS)/installEpics.pl $(QUIET_FLAG)
|
||||
|
@ -38,6 +38,8 @@ BUILD_ARCHS = $(EPICS_HOST_ARCH) $(CROSS1) $(CROSS2)
|
||||
# otherwise override this in os/CONFIG_SITE.<host_arch>.Common
|
||||
PERL = perl -CSD
|
||||
|
||||
PYTHON = python
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Check configure/RELEASE file for consistency
|
||||
CHECK_RELEASE_YES = checkRelease
|
||||
|
@ -169,10 +169,18 @@ EPICS_SITE_VERSION =
|
||||
GCC_PIPE = NO
|
||||
|
||||
# Set RPATH when linking executables and libraries.
|
||||
# Must be either YES or NO. If you set this to NO you must also provide a
|
||||
# Must be either YES, NO, or ORIGIN. If you set this to NO you must also provide a
|
||||
# way for Base executables to find their shared libraries when they are
|
||||
# run at build-time, e.g. set the LD_LIBRARY_PATH environment variable.
|
||||
# ORIGIN is a feature of the ELF executable format used by Linux, freebsd, and solaris.
|
||||
LINKER_USE_RPATH = YES
|
||||
|
||||
# Only used when LINKER_USE_RPATH=ORIGIN
|
||||
# The build time root(s) of the relocatable tree (separate multiple w/ ':').
|
||||
# Linking to libraries under any root directory will be relative.
|
||||
# Linking to libraries outside of this root will be absolute.
|
||||
# All root directories are considered to be the same.
|
||||
LINKER_ORIGIN_ROOT = $(INSTALL_LOCATION)
|
||||
|
||||
# Overrides for the settings above may appear in a CONFIG_SITE.local file
|
||||
-include $(CONFIG)/CONFIG_SITE.local
|
||||
|
@ -196,6 +196,13 @@ ifeq ($(EPICS_HOST_ARCH),$(T_A))
|
||||
$(info Warning: RELEASE file consistency checks have been disabled)
|
||||
endif
|
||||
|
||||
# $(FINAL_DIR) signals eventual install locations to makeRPath script
|
||||
$(TESTPRODNAME): FINAL_DIR=.
|
||||
$(PRODNAME): FINAL_DIR=$(INSTALL_BIN)
|
||||
$(TESTSHRLIBNAME): FINAL_DIR=.
|
||||
$(SHRLIBNAME): FINAL_DIR=$(INSTALL_SHRLIB)
|
||||
$(LOADABLE_SHRLIBNAME): FINAL_DIR=$(INSTALL_SHRLIB)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# The order of the following rules is
|
||||
# VERY IMPORTANT !!!!
|
||||
|
@ -25,11 +25,13 @@ STATIC_LDLIBS_YES= -Wl,-Bdynamic
|
||||
|
||||
# Set runtime path for shared libraries if LINKER_USE_RPATH=YES
|
||||
SHRLIBDIR_RPATH_LDFLAGS_YES = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%)
|
||||
SHRLIBDIR_RPATH_LDFLAGS_ORIGIN = $(shell $(MAKERPATH) -O '\$$ORIGIN' -F $(FINAL_DIR) -R $(LINKER_ORIGIN_ROOT) $(SHRLIB_DEPLIB_DIRS))
|
||||
SHRLIBDIR_LDFLAGS += \
|
||||
$(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
|
||||
|
||||
# Set runtime path for products if LINKER_USE_RPATH=YES
|
||||
PRODDIR_RPATH_LDFLAGS_YES = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%)
|
||||
PRODDIR_RPATH_LDFLAGS_ORIGIN = $(shell $(MAKERPATH) -O '\$$ORIGIN' -F $(FINAL_DIR) -R $(LINKER_ORIGIN_ROOT) $(PROD_DEPLIB_DIRS))
|
||||
PRODDIR_LDFLAGS += \
|
||||
$(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH))
|
||||
|
||||
|
@ -9,225 +9,237 @@
|
||||
|
||||
/* Author: Andrew Johnson Date: 2003-04-08 */
|
||||
|
||||
/* Usage:
|
||||
* softIoc [-D softIoc.dbd] [-h] [-S] [-s] [-a ascf]
|
||||
* [-m macro=value,macro2=value2] [-d file.db]
|
||||
* [-x prefix] [st.cmd]
|
||||
*
|
||||
* If used the -D option must come first, and specify the
|
||||
* path to the softIoc.dbd file. The compile-time install
|
||||
* location is saved in the binary as a default.
|
||||
*
|
||||
* Usage information will be printed if -h is given, then
|
||||
* the program will exit normally.
|
||||
*
|
||||
* The -S option prevents an interactive shell being started
|
||||
* after all arguments have been processed.
|
||||
*
|
||||
* Previous versions accepted a -s option to cause a shell
|
||||
* to be started; this option is still accepted but ignored
|
||||
* since a command shell is now started by default.
|
||||
*
|
||||
* Access Security can be enabled with the -a option giving
|
||||
* the name of the configuration file; if any macros were
|
||||
* set with -m before the -a option was given, they will be
|
||||
* used as access security substitution macros.
|
||||
*
|
||||
* Any number of -m and -d arguments can be interspersed;
|
||||
* the macros are applied to the following .db files. Each
|
||||
* later -m option causes earlier macros to be discarded.
|
||||
*
|
||||
* The -x option loads the softIocExit.db with the macro
|
||||
* IOC set to the string provided. This database contains
|
||||
* a subroutine record named $(IOC):exit which has its field
|
||||
* SNAM set to "exit". When this record is processed, the
|
||||
* subroutine that runs will call epicsExit() with the value
|
||||
* of the field A determining whether the exit status is
|
||||
* EXIT_SUCCESS if (A == 0.0) or EXIT_FAILURE (A != 0.0).
|
||||
*
|
||||
* A st.cmd file is optional. If any databases were loaded
|
||||
* the st.cmd file will be run *after* iocInit. To perform
|
||||
* iocsh commands before iocInit, all database loading must
|
||||
* be performed by the script itself, or by the user from
|
||||
* the interactive IOC shell.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <epicsGetopt.h>
|
||||
#include "registryFunction.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsExit.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsString.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "subRecord.h"
|
||||
#include "dbAccess.h"
|
||||
#include "asDbLib.h"
|
||||
#include "iocInit.h"
|
||||
#include "iocsh.h"
|
||||
#include "osiFileName.h"
|
||||
#include "epicsInstallDir.h"
|
||||
|
||||
extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase);
|
||||
|
||||
#define DBD_FILE EPICS_BASE "/dbd/softIoc.dbd"
|
||||
#define EXIT_FILE EPICS_BASE "/db/softIocExit.db"
|
||||
#ifndef EPICS_BASE
|
||||
// so IDEs knows EPICS_BASE is a string constant
|
||||
# define EPICS_BASE "/"
|
||||
# error -DEPICS_BASE required
|
||||
#endif
|
||||
|
||||
const char *arg0;
|
||||
const char *base_dbd = DBD_FILE;
|
||||
const char *exit_db = EXIT_FILE;
|
||||
#define DBD_BASE "dbd/softIoc.dbd"
|
||||
#define EXIT_BASE "db/softIocExit.db"
|
||||
#define DBD_FILE_REL "../../" DBD_BASE
|
||||
#define EXIT_FILE_REL "../../" EXIT_BASE
|
||||
#define DBD_FILE EPICS_BASE "/" DBD_BASE
|
||||
#define EXIT_FILE EPICS_BASE "/" EXIT_BASE
|
||||
|
||||
namespace {
|
||||
|
||||
static void exitSubroutine(subRecord *precord) {
|
||||
epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void usage(int status) {
|
||||
printf("Usage: %s [-D softIoc.dbd] [-h] [-S] [-a ascf]\n", arg0);
|
||||
puts("\t[-m macro=value,macro2=value2] [-d file.db]");
|
||||
puts("\t[-x prefix] [st.cmd]");
|
||||
puts("Compiled-in path to softIoc.dbd is:");
|
||||
printf("\t%s\n", base_dbd);
|
||||
epicsExit(status);
|
||||
void usage(const char *arg0, const std::string& base_dbd) {
|
||||
std::cout<<"Usage: "<<arg0<<
|
||||
" [-D softIoc.dbd] [-h] [-S] [-s] [-a ascf]\n"
|
||||
"[-m macro=value,macro2=value2] [-d file.db]\n"
|
||||
"[-x prefix] [st.cmd]\n"
|
||||
"\n"
|
||||
" -D <dbd> If used, must come first. Specify the path to the softIoc.dbdfile."
|
||||
" The compile-time install location is saved in the binary as a default.\n"
|
||||
"\n"
|
||||
" -h Print this mesage and exit.\n"
|
||||
"\n"
|
||||
" -S Prevents an interactive shell being started.\n"
|
||||
"\n"
|
||||
" -s Previously caused a shell to be started. Now accepted and ignored.\n"
|
||||
"\n"
|
||||
" -a <acf> Access Security configuration file. Macro substitution is\n"
|
||||
" performed.\n"
|
||||
"\n"
|
||||
" -m <MAC>=<value>,... Set/replace macro definitions used by subsequent -d and\n"
|
||||
" -a.\n"
|
||||
"\n"
|
||||
" -d <db> Load records from file (dbLoadRecords). Macro substitution is\n"
|
||||
" performed.\n"
|
||||
"\n"
|
||||
" -x <prefix> Load softIocExit.db. Provides a record \"<prefix>:exit\".\n"
|
||||
" Put 0 to exit with success, or non-zero to exit with an error.\n"
|
||||
"\n"
|
||||
"Any number of -m and -d arguments can be interspersed; the macros are applied\n"
|
||||
"to the following .db files. Each later -m option causes earlier macros to be\n"
|
||||
"discarded.\n"
|
||||
"\n"
|
||||
"A st.cmd file is optional. If any databases were loaded the st.cmd file will\n"
|
||||
"be run *after* iocInit. To perform iocsh commands before iocInit, all database\n"
|
||||
"loading must be performed by the script itself, or by the user from the\n"
|
||||
"interactive IOC shell.\n"
|
||||
"\n"
|
||||
"Compiled-in path to softIoc.dbd is:\n"
|
||||
"\t"<<base_dbd.c_str()<<"\n";
|
||||
}
|
||||
|
||||
void errIf(int ret, const std::string& msg)
|
||||
{
|
||||
if(ret)
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
void lazy_dbd(const std::string& dbd_file) {
|
||||
static bool loaded;
|
||||
if(loaded) return;
|
||||
loaded = true;
|
||||
|
||||
errIf(dbLoadDatabase(dbd_file.c_str(), NULL, NULL),
|
||||
std::string("Failed to load DBD file: ")+dbd_file);
|
||||
std::cout<<"dbLoadDatabase(\""<<dbd_file<<"\")\n";
|
||||
|
||||
softIoc_registerRecordDeviceDriver(pdbbase);
|
||||
std::cout<<"softIoc_registerRecordDeviceDriver(pdbbase)\n";
|
||||
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *dbd_file = const_cast<char*>(base_dbd);
|
||||
char *macros = NULL;
|
||||
char xmacro[PVNAME_STRINGSZ + 4];
|
||||
int startIocsh = 1; /* default = start shell */
|
||||
int loadedDb = 0;
|
||||
|
||||
arg0 = strrchr(*argv, '/');
|
||||
if (!arg0) {
|
||||
arg0 = *argv;
|
||||
} else {
|
||||
++arg0; /* skip the '/' */
|
||||
}
|
||||
|
||||
--argc, ++argv;
|
||||
|
||||
/* Do this here in case the dbd file not available */
|
||||
if (argc>0 && **argv=='-' && (*argv)[1]=='h') {
|
||||
usage(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (argc>1 && **argv=='-' && (*argv)[1]=='D') {
|
||||
dbd_file = *++argv;
|
||||
argc -= 2;
|
||||
++argv;
|
||||
}
|
||||
|
||||
if (dbLoadDatabase(dbd_file, NULL, NULL)) {
|
||||
epicsExit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
softIoc_registerRecordDeviceDriver(pdbbase);
|
||||
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
|
||||
try {
|
||||
std::string dbd_file(DBD_FILE),
|
||||
exit_file(EXIT_FILE),
|
||||
macros, // scratch space for macros (may be given more than once)
|
||||
xmacro;
|
||||
bool interactive = true;
|
||||
bool loadedDb = false;
|
||||
|
||||
while (argc>1 && **argv == '-') {
|
||||
switch ((*argv)[1]) {
|
||||
case 'a':
|
||||
if (macros) asSetSubstitutions(macros);
|
||||
asSetFilename(*++argv);
|
||||
--argc;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (dbLoadRecords(*++argv, macros)) {
|
||||
epicsExit(EXIT_FAILURE);
|
||||
}
|
||||
loadedDb = 1;
|
||||
--argc;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(EXIT_SUCCESS);
|
||||
|
||||
case 'm':
|
||||
macros = *++argv;
|
||||
--argc;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
startIocsh = 0;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
epicsSnprintf(xmacro, sizeof xmacro, "IOC=%s", *++argv);
|
||||
if (dbLoadRecords(exit_db, xmacro)) {
|
||||
epicsExit(EXIT_FAILURE);
|
||||
}
|
||||
loadedDb = 1;
|
||||
--argc;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: option '%s' not recognized\n", arg0, *argv);
|
||||
usage(EXIT_FAILURE);
|
||||
}
|
||||
--argc;
|
||||
++argv;
|
||||
// attempt to compute relative paths
|
||||
{
|
||||
std::string prefix;
|
||||
char *cprefix = epicsGetExecDir();
|
||||
if(cprefix) {
|
||||
try {
|
||||
prefix = cprefix;
|
||||
free(cprefix);
|
||||
} catch(...) {
|
||||
free(cprefix);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
dbd_file = prefix + DBD_FILE_REL;
|
||||
exit_file = prefix + EXIT_FILE_REL;
|
||||
}
|
||||
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "ha:d:m:Ssx:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h': /* Print usage */
|
||||
usage(argv[0], dbd_file);
|
||||
epicsExit(0);
|
||||
return 0;
|
||||
default:
|
||||
usage(argv[0], dbd_file);
|
||||
std::cerr<<"Unknown argument: -"<<char(opt)<<"\n";
|
||||
epicsExit(2);
|
||||
return 2;
|
||||
case 'a':
|
||||
lazy_dbd(dbd_file);
|
||||
if (!macros.empty()) {
|
||||
if(asSetSubstitutions(macros.c_str()))
|
||||
throw std::bad_alloc();
|
||||
std::cout<<"asSetSubstitutions(\""<<macros<<"\")\n";
|
||||
}
|
||||
if(asSetFilename(optarg))
|
||||
throw std::bad_alloc();
|
||||
std::cout<<"asSetFilename(\""<<optarg<<"\")\n";
|
||||
break;
|
||||
case 'd':
|
||||
lazy_dbd(dbd_file);
|
||||
errIf(dbLoadRecords(optarg, macros.c_str()),
|
||||
std::string("Failed to load: ")+optarg);
|
||||
std::cout<<"dbLoadRecords(\""<<optarg<<"\"";
|
||||
if(!macros.empty())
|
||||
std::cout<<", \""<<macros<<"\"";
|
||||
std::cout<<")\n";
|
||||
loadedDb = true;
|
||||
break;
|
||||
case 'm':
|
||||
macros = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
interactive = false;
|
||||
break;
|
||||
case 's':
|
||||
break; // historical
|
||||
case 'x':
|
||||
lazy_dbd(dbd_file);
|
||||
xmacro = "IOC=";
|
||||
xmacro += optarg;
|
||||
errIf(dbLoadRecords(exit_file.c_str(), xmacro.c_str()),
|
||||
std::string("Failed to load: ")+exit_file);
|
||||
loadedDb = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lazy_dbd(dbd_file);
|
||||
|
||||
if(optind<argc) {
|
||||
// run script
|
||||
// ignore any extra positional args (historical)
|
||||
|
||||
std::cout<<"# Begin "<<argv[optind]<<"\n";
|
||||
errIf(iocsh(argv[optind]),
|
||||
std::string("Error in ")+argv[optind]);
|
||||
std::cout<<"# End "<<argv[optind]<<"\n";
|
||||
|
||||
epicsThreadSleep(0.2);
|
||||
loadedDb = true; /* Give it the benefit of the doubt... */
|
||||
}
|
||||
|
||||
if (loadedDb) {
|
||||
std::cout<<"iocInit()\n";
|
||||
iocInit();
|
||||
epicsThreadSleep(0.2);
|
||||
}
|
||||
|
||||
if(interactive) {
|
||||
std::cout.flush();
|
||||
std::cerr.flush();
|
||||
if(iocsh(NULL)) {
|
||||
epicsExit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (loadedDb) {
|
||||
epicsThreadExitMain();
|
||||
|
||||
} else {
|
||||
usage(argv[0], dbd_file);
|
||||
std::cerr<<"Nothing to do!\n";
|
||||
epicsExit(1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
epicsExit(0);
|
||||
return 0;
|
||||
|
||||
}catch(std::exception& e){
|
||||
std::cerr<<"Error: "<<e.what()<<"\n";
|
||||
epicsExit(2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (argc>0 && **argv=='-') {
|
||||
switch((*argv)[1]) {
|
||||
case 'a':
|
||||
case 'd':
|
||||
case 'm':
|
||||
case 'x':
|
||||
printf("%s: missing argument to option '%s'\n", arg0, *argv);
|
||||
usage(EXIT_FAILURE);
|
||||
|
||||
case 'h':
|
||||
usage(EXIT_SUCCESS);
|
||||
|
||||
case 'S':
|
||||
startIocsh = 0;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s: option '%s' not recognized\n", arg0, *argv);
|
||||
usage(EXIT_FAILURE);
|
||||
}
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
|
||||
if (loadedDb) {
|
||||
iocInit();
|
||||
epicsThreadSleep(0.2);
|
||||
}
|
||||
|
||||
/* run user's startup script */
|
||||
if (argc>0) {
|
||||
if (iocsh(*argv)) epicsExit(EXIT_FAILURE);
|
||||
epicsThreadSleep(0.2);
|
||||
loadedDb = 1; /* Give it the benefit of the doubt... */
|
||||
}
|
||||
|
||||
/* start an interactive shell if it was requested */
|
||||
if (startIocsh) {
|
||||
iocsh(NULL);
|
||||
} else {
|
||||
if (loadedDb) {
|
||||
epicsThreadExitMain();
|
||||
} else {
|
||||
printf("%s: Nothing to do!\n", arg0);
|
||||
usage(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
epicsExit(EXIT_SUCCESS);
|
||||
/*Note that the following statement will never be executed*/
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,7 +14,29 @@
|
||||
#ifndef unixFileNameH
|
||||
#define unixFileNameH
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OSI_PATH_LIST_SEPARATOR ":"
|
||||
#define OSI_PATH_SEPARATOR "/"
|
||||
|
||||
/** Return the absolute path of the current executable.
|
||||
@returns NULL or the path. Caller must free()
|
||||
*/
|
||||
epicsShareFunc
|
||||
char *epicsGetExecName(void);
|
||||
|
||||
/** Return the absolute path of the directory containing the current executable.
|
||||
@returns NULL or the path. Caller must free()
|
||||
*/
|
||||
epicsShareFunc
|
||||
char *epicsGetExecDir(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* unixFileNameH */
|
||||
|
@ -123,6 +123,7 @@ Com_SRCS += osdMonotonic.c
|
||||
Com_SRCS += osdProcess.c
|
||||
Com_SRCS += osdNetIntf.c
|
||||
Com_SRCS += osdMessageQueue.c
|
||||
Com_SRCS += osdgetexec.c
|
||||
|
||||
Com_SRCS += devLibVME.c
|
||||
Com_SRCS += devLibVMEOSD.c
|
||||
|
50
modules/libcom/src/osi/os/Darwin/osdgetexec.c
Normal file
50
modules/libcom/src/osi/os/Darwin/osdgetexec.c
Normal file
@ -0,0 +1,50 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <mach-o/dyld.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <osiFileName.h>
|
||||
|
||||
char *epicsGetExecName(void)
|
||||
{
|
||||
uint32_t max = 64u;
|
||||
char *ret = NULL;
|
||||
|
||||
while(1) {
|
||||
char *temp = realloc(ret, max);
|
||||
if(!temp) {
|
||||
/* we treat alloc failure as terminal */
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
break;
|
||||
}
|
||||
ret = temp;
|
||||
|
||||
/* cf. "man 3 dyld" */
|
||||
if(_NSGetExecutablePath(ret, &max)==0) {
|
||||
/* max left unchanged */
|
||||
ret[max-1] = '\0';
|
||||
break;
|
||||
}
|
||||
/* max has been updated with required size */
|
||||
}
|
||||
|
||||
/* TODO: _NSGetExecutablePath() doesn't follow symlinks */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *epicsGetExecDir(void)
|
||||
{
|
||||
char *ret = epicsGetExecName();
|
||||
if(ret) {
|
||||
char *sep = strrchr(ret, '/');
|
||||
if(sep) {
|
||||
/* nil the charactor after the / */
|
||||
sep[1] = '\0';
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
54
modules/libcom/src/osi/os/Linux/osdgetexec.c
Normal file
54
modules/libcom/src/osi/os/Linux/osdgetexec.c
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <osiFileName.h>
|
||||
|
||||
char *epicsGetExecName(void)
|
||||
{
|
||||
size_t max = PATH_MAX;
|
||||
char *ret = NULL;
|
||||
ssize_t n;
|
||||
|
||||
while(1) {
|
||||
char *temp = realloc(ret, max);
|
||||
if(!temp) {
|
||||
/* we treat alloc failure as terminal */
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
break;
|
||||
}
|
||||
ret = temp;
|
||||
|
||||
n = readlink("/proc/self/exe", ret, max);
|
||||
if(n == -1) {
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
break;
|
||||
} else if(n < max) {
|
||||
/* readlink() never adds a nil */
|
||||
ret[n] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
max += 64;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *epicsGetExecDir(void)
|
||||
{
|
||||
char *ret = epicsGetExecName();
|
||||
if(ret) {
|
||||
char *sep = strrchr(ret, '/');
|
||||
if(sep) {
|
||||
/* nil the charactor after the / */
|
||||
sep[1] = '\0';
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
52
modules/libcom/src/osi/os/WIN32/osdgetexec.c
Normal file
52
modules/libcom/src/osi/os/WIN32/osdgetexec.c
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <osiFileName.h>
|
||||
|
||||
char *epicsGetExecName(void)
|
||||
{
|
||||
size_t max = 128;
|
||||
char *ret = NULL;
|
||||
DWORD n;
|
||||
|
||||
while(1) {
|
||||
char *temp = realloc(ret, max);
|
||||
if(!temp) {
|
||||
/* we treat alloc failure as terminal */
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
break;
|
||||
}
|
||||
ret = temp;
|
||||
|
||||
n = GetModuleFileName(NULL, ret, max);
|
||||
if(n == 0) {
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
break;
|
||||
} else if(n < max) {
|
||||
ret[n] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
max += 64;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *epicsGetExecDir(void)
|
||||
{
|
||||
char *ret = epicsGetExecName();
|
||||
if(ret) {
|
||||
char *sep = strrchr(ret, '\\');
|
||||
if(sep) {
|
||||
/* nil the charactor after the / */
|
||||
sep[1] = '\0';
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -15,7 +15,29 @@
|
||||
#ifndef osiFileNameH
|
||||
#define osiFileNameH
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OSI_PATH_LIST_SEPARATOR ";"
|
||||
#define OSI_PATH_SEPARATOR "\\"
|
||||
|
||||
/** Return the absolute path of the current executable.
|
||||
@returns NULL or the path. Caller must free()
|
||||
*/
|
||||
epicsShareFunc
|
||||
char *epicsGetExecName(void);
|
||||
|
||||
/** Return the absolute path of the directory containing the current executable.
|
||||
@returns NULL or the path. Caller must free()
|
||||
*/
|
||||
epicsShareFunc
|
||||
char *epicsGetExecDir(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* osiFileNameH */
|
||||
|
@ -14,7 +14,29 @@
|
||||
#ifndef osiFileNameH
|
||||
#define osiFileNameH
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OSI_PATH_LIST_SEPARATOR ";"
|
||||
#define OSI_PATH_SEPARATOR "\\"
|
||||
|
||||
/** Return the absolute path of the current executable.
|
||||
@returns NULL or the path. Caller must free()
|
||||
*/
|
||||
epicsShareFunc
|
||||
char *epicsGetExecName(void);
|
||||
|
||||
/** Return the absolute path of the directory containing the current executable.
|
||||
@returns NULL or the path. Caller must free()
|
||||
*/
|
||||
epicsShareFunc
|
||||
char *epicsGetExecDir(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* osiFileNameH */
|
||||
|
14
modules/libcom/src/osi/os/default/osdgetexec.c
Normal file
14
modules/libcom/src/osi/os/default/osdgetexec.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <osiFileName.h>
|
||||
|
||||
char *epicsGetExecName(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *epicsGetExecDir(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
68
modules/libcom/src/osi/os/freebsd/osdgetexec.c
Normal file
68
modules/libcom/src/osi/os/freebsd/osdgetexec.c
Normal file
@ -0,0 +1,68 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <osiFileName.h>
|
||||
|
||||
char *epicsGetExecName(void)
|
||||
{
|
||||
size_t max = PATH_MAX;
|
||||
char *ret = NULL;
|
||||
ssize_t n;
|
||||
|
||||
while(1) {
|
||||
char *temp = realloc(ret, max);
|
||||
if(!temp) {
|
||||
/* we treat alloc failure as terminal */
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
break;
|
||||
}
|
||||
ret = temp;
|
||||
|
||||
n = readlink("/proc/curproc/file", ret, max);
|
||||
if(n == -1) {
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
break;
|
||||
} else if(n < max) {
|
||||
/* readlink() never adds a nil */
|
||||
ret[n] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
max += 64;
|
||||
}
|
||||
|
||||
if(!ret) {
|
||||
int mib[4];
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PATHNAME;
|
||||
mib[3] = -1;
|
||||
|
||||
ret = malloc(max);
|
||||
if(ret) {
|
||||
sysctl(mib, 4, ret, &cb, NULL, 0);
|
||||
/* TODO: error check */
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *epicsGetExecDir(void)
|
||||
{
|
||||
char *ret = epicsGetExecName();
|
||||
if(ret) {
|
||||
char *sep = strrchr(ret, '/');
|
||||
if(sep) {
|
||||
/* nil the charactor after the / */
|
||||
sep[1] = '\0';
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
30
modules/libcom/src/osi/os/solaris/osdgetexec.c
Normal file
30
modules/libcom/src/osi/os/solaris/osdgetexec.c
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <osiFileName.h>
|
||||
|
||||
char *epicsGetExecName(void)
|
||||
{
|
||||
const char *raw = getexecname();
|
||||
char *ret = NULL;
|
||||
/* manpage says getexecname() might return a relative path. we treat this as an error */
|
||||
if(raw[0]=='/') {
|
||||
ret = strdup(raw);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *epicsGetExecDir(void)
|
||||
{
|
||||
char *ret = epicsGetExecName();
|
||||
if(ret) {
|
||||
char *sep = strrchr(ret, '/');
|
||||
if(sep) {
|
||||
/* nil the charactor after the / */
|
||||
sep[1] = '\0';
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -232,6 +232,11 @@ osiSockTest_SRCS += osiSockTest.c
|
||||
testHarness_SRCS += osiSockTest.c
|
||||
TESTS += osiSockTest
|
||||
|
||||
TESTPROD_HOST += testexecname
|
||||
testexecname_SRCS += testexecname.c
|
||||
# no point in including in testHarness. Not implemented for RTEMS/vxWorks.
|
||||
TESTS += testexecname
|
||||
|
||||
ifeq ($(BUILD_CLASS),HOST)
|
||||
ifneq ($(OS_CLASS),WIN32)
|
||||
# This test can only be run on a build host, and is broken on Windows
|
||||
|
24
modules/libcom/test/testexecname.c
Normal file
24
modules/libcom/test/testexecname.c
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <epicsUnitTest.h>
|
||||
#include <testMain.h>
|
||||
|
||||
#include <osiFileName.h>
|
||||
|
||||
MAIN(testexecname)
|
||||
{
|
||||
testPlan(1);
|
||||
|
||||
{
|
||||
char *buf = epicsGetExecName();
|
||||
if(!buf) {
|
||||
testSkip(1, "epicsGetExecName() not available for this target");
|
||||
} else {
|
||||
char *loc = strstr(buf, "testexecname");
|
||||
testOk(!!loc, "Find \"testexecname\" in \"%s\"", buf);
|
||||
}
|
||||
}
|
||||
|
||||
return testDone();
|
||||
}
|
@ -39,6 +39,8 @@ PERL_SCRIPTS += tap-to-junit-xml.pl
|
||||
PERL_SCRIPTS += useManifestTool.pl
|
||||
PERL_SCRIPTS += genVersionHeader.pl
|
||||
|
||||
PERL_SCRIPTS += makeRPath.py
|
||||
|
||||
HTMLS = style.css
|
||||
HTMLS += EPICS/Getopts.html
|
||||
HTMLS += EPICS/Path.html
|
||||
|
80
src/tools/makeRPath.py
Normal file
80
src/tools/makeRPath.py
Normal file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import os
|
||||
from collections import OrderedDict # used as OrderedSet
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
if os.environ.get('EPICS_DEBUG_RPATH','')=='YES':
|
||||
sys.stderr.write('%s'%sys.argv)
|
||||
|
||||
P = ArgumentParser(description='''Compute and output -rpath entries for each of the given paths.
|
||||
Paths under --root will be computed as relative to --final .''',
|
||||
epilog='''
|
||||
eg. A library to be placed in /build/lib and linked against libraries in
|
||||
'/build/lib', '/build/module/lib', and '/other/lib' would pass:
|
||||
|
||||
"makeRPath.py -F /build/lib -R /build /build/lib /build/module/lib /other/lib"
|
||||
which prints "-Wl,-rpath,$ORIGIN/. -Wl,-rpath,$ORIGIN/../module/lib -Wl,-rpath,/other/lib"
|
||||
''')
|
||||
P.add_argument('-F','--final',default=os.getcwd(), help='Final install location for ELF file')
|
||||
P.add_argument('-R','--root',default='', help='Root(s) of relocatable tree. Separate with :')
|
||||
P.add_argument('-O', '--origin', default='$ORIGIN')
|
||||
P.add_argument('path', nargs='*')
|
||||
args = P.parse_args()
|
||||
|
||||
# eg.
|
||||
# target to be installed as: /build/bin/blah
|
||||
#
|
||||
# post-install will copy as: /install/bin/blah
|
||||
#
|
||||
# Need to link against:
|
||||
# /install/lib/libA.so
|
||||
# /build/lib/libB.so
|
||||
# /other/lib/libC.so
|
||||
#
|
||||
# Want final result to be:
|
||||
# -rpath $ORIGIN/../lib -rpath /other/lib \
|
||||
# -rpath-link /build/lib -rpath-link /install/lib
|
||||
|
||||
fdir = os.path.abspath(args.final)
|
||||
roots = [os.path.abspath(root) for root in args.root.split(':') if len(root)]
|
||||
|
||||
# find the root which contains the final location
|
||||
froot = None
|
||||
for root in roots:
|
||||
frel = os.path.relpath(fdir, root)
|
||||
if not frel.startswith('..'):
|
||||
# final dir is under this root
|
||||
froot = root
|
||||
break
|
||||
|
||||
if froot is None:
|
||||
sys.stderr.write("makeRPath: Final location %s\nNot under any of: %s\n"%(fdir, roots))
|
||||
sys.exit(1)
|
||||
|
||||
output = OrderedDict()
|
||||
for path in args.path:
|
||||
path = os.path.abspath(path)
|
||||
|
||||
for root in roots:
|
||||
rrel = os.path.relpath(path, root)
|
||||
if not rrel.startswith('..'):
|
||||
# path is under this root
|
||||
|
||||
# some older binutils don't seem to handle $ORIGIN correctly
|
||||
# when locating dependencies of libraries. So also provide
|
||||
# the absolute path for internal use by 'ld' only.
|
||||
output['-Wl,-rpath-link,'+path] = True
|
||||
|
||||
# frel is final location relative to enclosing root
|
||||
# rrel is target location relative to enclosing root
|
||||
path = os.path.relpath(rrel, frel)
|
||||
break
|
||||
|
||||
output['-Wl,-rpath,'+os.path.join(args.origin, path)] = True
|
||||
|
||||
print(' '.join(output))
|
Reference in New Issue
Block a user