aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/CMakeLists.txt5
-rw-r--r--lib/error_handler.c1
-rw-r--r--lib/install.c1
-rw-r--r--lib/internal_cmd.c9
-rw-r--r--lib/rpath.c120
-rw-r--r--lib/shlib.c91
6 files changed, 160 insertions, 67 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 2185ef4..96147e1 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -1,6 +1,8 @@
include_directories(
${CMAKE_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}/include
+ ${OpenSSL_INCLUDE_DIRS}
+ ${CURL_INCLUDE_DIRS}
)
set(libspm_src
@@ -39,7 +41,8 @@ add_library(libspm SHARED $<TARGET_OBJECTS:libspm_obj>)
add_library(libspm_static STATIC $<TARGET_OBJECTS:libspm_obj>)
-target_link_libraries(libspm crypto ssl curl)
+target_link_directories(libspm PUBLIC ${OpenSSL_LIBRARY_DIRS} ${CURL_LIBRARY_DIRS})
+target_link_libraries(libspm ${OpenSSL_LIBRARIES} ${CURL_LIBRARIES})
if (LINUX)
target_link_libraries(libspm rt)
endif()
diff --git a/lib/error_handler.c b/lib/error_handler.c
index aa48274..2ccb4e7 100644
--- a/lib/error_handler.c
+++ b/lib/error_handler.c
@@ -14,6 +14,7 @@ const char *SPM_ERR_STRING[] = {
"Manifest has no header",
"Manifest has no data",
"Parsing error",
+ "Not implemented",
NULL,
};
diff --git a/lib/install.c b/lib/install.c
index 32348e2..9fb80c2 100644
--- a/lib/install.c
+++ b/lib/install.c
@@ -278,6 +278,7 @@ int spm_do_install(SPM_Hierarchy *fs, ManifestList *mf, StrList *packages) {
if (package_path == NULL) {
free(package_path);
free(package_localpath);
+ // TODO: set spmerrno here
exit(1);
}
fetched = 1;
diff --git a/lib/internal_cmd.c b/lib/internal_cmd.c
index 6f6b1c6..a859b5b 100644
--- a/lib/internal_cmd.c
+++ b/lib/internal_cmd.c
@@ -218,7 +218,11 @@ int mkruntime_interface(int argc, char **argv) {
runtime_set(rt, "SPM_MAN", fs->mandir);
runtime_set(rt, "SPM_LOCALSTATE", fs->localstatedir);
runtime_set(rt, "SPM_PKGCONFIG", spm_pkgconfigdir);
+#if OS_DARWIN
+ runtime_set(rt, "SPM_PKGCONFIG", "${SPM_PKGCONFIG}:${SPM_DATA}/pkgconfig");
+#elif OS_LINUX
runtime_set(rt, "SPM_PKGCONFIG", "${SPM_PKGCONFIG}:${SPM_LIB64}/pkgconfig:${SPM_DATA}/pkgconfig");
+#endif
runtime_set(rt, "SPM_META_DEPENDS", SPM_META_DEPENDS);
runtime_set(rt, "SPM_META_PREFIX_BIN", SPM_META_PREFIX_BIN);
runtime_set(rt, "SPM_META_PREFIX_TEXT", SPM_META_PREFIX_TEXT);
@@ -236,9 +240,10 @@ int mkruntime_interface(int argc, char **argv) {
runtime_set(rt, "CC", "$SPM_BIN/gcc");
}
- runtime_set(rt, "CFLAGS", "-I$SPM_INCLUDE $CFLAGS");
+ runtime_set(rt, "CFLAGS", "-I$SPM_INCLUDE");
#if OS_DARWIN
- runtime_set(rt, "LDFLAGS", "-rpath $SPM_LIB:$SPM_LIB64 -L$SPM_LIB -L$SPM_LIB64 $LDFLAGS");
+ // For now `reloc` can fix up the LC_ID_DYLIB on its own without install_name_tool
+ runtime_set(rt, "LDFLAGS", "-rpath $SPM_LIB -L$SPM_LIB");
#elif OS_LINUX
runtime_set(rt, "LDFLAGS", "-Wl,-rpath=$SPM_LIB:$SPM_LIB64 -L$SPM_LIB -L$SPM_LIB64 $LDFLAGS");
#else
diff --git a/lib/rpath.c b/lib/rpath.c
index 4d4d801..ae73574 100644
--- a/lib/rpath.c
+++ b/lib/rpath.c
@@ -5,7 +5,7 @@
/**
* Wrapper function to execute `patchelf` with arguments
- * @param _filename Path of file to modify
+ * @param _filename Path to file
* @param _args Arguments to pass to `patchelf`
* @return success=Process struct, failure=NULL
*/
@@ -32,6 +32,34 @@ Process *patchelf(const char *_filename, const char *_args) {
}
/**
+ * Wrapper function to execute `install_name_tool` with arguments
+ * @param _filename Path to file
+ * @param _args Arguments to pass to `install_name_tool`
+ * @return success=Process struct, failure=NULL
+ */
+Process *install_name_tool(const char *_filename, const char *_args) {
+ char *filename = strdup(_filename);
+ char *args = strdup(_args);
+ Process *proc_info = NULL;
+ char sh_cmd[PATH_MAX];
+ sh_cmd[0] = '\0';
+
+ strchrdel(args, SHELL_INVALID);
+ strchrdel(filename, SHELL_INVALID);
+ sprintf(sh_cmd, "install_name_tool %s %s 2>&1", args, filename);
+
+ if (SPM_GLOBAL.verbose > 1) {
+ printf(" EXEC : %s\n", sh_cmd);
+ }
+
+ shell(&proc_info, SHELL_OUTPUT, sh_cmd);
+
+ free(filename);
+ free(args);
+ return proc_info;
+}
+
+/**
* Determine whether a RPATH or RUNPATH is present in file
*
* TODO: Replace with OS-native solution(s)
@@ -40,30 +68,18 @@ Process *patchelf(const char *_filename, const char *_args) {
* @return -1=OS error, 0=has rpath, 1=not found
*/
int has_rpath(const char *_filename) {
- int result = 1; // default: not found
+ char *rpath = NULL;
- char *filename = strdup(_filename);
- if (!filename) {
+ if (_filename == NULL) {
+ spmerrno = EINVAL;
return -1;
}
- // sanitize input path
- strchrdel(filename, SHELL_INVALID);
-
- Process *pe = patchelf(filename, "--print-rpath");
- strip(pe->output);
- if (!isempty(pe->output)) {
- result = 0;
- }
- else {
- // something went wrong with patchelf other than
- // what we're looking for
- result = -1;
- }
+ if ((rpath = shlib_rpath(_filename)) == NULL) {
+ return 1;
+ };
- free(filename);
- shell_free(pe);
- return result;
+ return 0;
}
/**
@@ -78,42 +94,7 @@ char *rpath_get(const char *_filename) {
if ((has_rpath(_filename)) != 0) {
return strdup("");
}
- char *filename = strdup(_filename);
- if (!filename) {
- return NULL;
- }
- char *path = strdup(filename);
- if (!path) {
- free(filename);
- return NULL;
- }
-
- char *rpath = NULL;
-
- // sanitize input path
- strchrdel(path, SHELL_INVALID);
-
- Process *pe = patchelf(filename, "--print-rpath");
- if (pe->returncode != 0) {
- fprintf(stderr, "patchelf error: %s %s\n", path, strip(pe->output));
- return NULL;
- }
-
- rpath = (char *)calloc(strlen(pe->output) + 1, sizeof(char));
- if (!rpath) {
- free(filename);
- free(path);
- shell_free(pe);
- return NULL;
- }
-
- strncpy(rpath, pe->output, strlen(pe->output));
- strip(rpath);
-
- free(filename);
- free(path);
- shell_free(pe);
- return rpath;
+ return shlib_rpath(_filename);
}
/**
@@ -149,10 +130,19 @@ char *rpath_generate(const char *_filename, FSTree *tree) {
int rpath_set(const char *filename, const char *rpath) {
int returncode = 0;
char args[PATH_MAX];
+ Process *pe = NULL;
memset(args, '\0', PATH_MAX);
- sprintf(args, "--set-rpath '%s'", rpath); // note: rpath requires single-quotes
- Process *pe = patchelf(filename, args);
+#if OS_LINUX
+ sprintf(args, "--set-rpath '%s'", rpath);
+ pe = patchelf(filename, args);
+#elif OS_DARWIN
+ sprintf(args, "-add-rpath '%s'", rpath);
+ pe = install_name_tool(filename, args);
+#elif OS_WINDOWS
+ // TODO: assuming windows has a mechanism for changing runtime paths, do it here.
+#endif
+
if (pe != NULL) {
returncode = pe->returncode;
}
@@ -203,7 +193,7 @@ FSTree *rpath_libraries_available(const char *root) {
* @return success=relative path from `filename` to nearest lib directory, failure=NULL
*/
char *rpath_autodetect(const char *filename, FSTree *tree) {
- const char *origin = "$ORIGIN";
+ const char *origin;
char *rootdir = dirname(filename);
char *start = realpath(rootdir, NULL);
char *cwd = realpath(".", NULL);
@@ -214,6 +204,14 @@ char *rpath_autodetect(const char *filename, FSTree *tree) {
char *relative = _relative; // Pointer to relative path
size_t depth_to_root = 0;
+#if OS_DARWIN
+ origin = "@rpath";
+#elif OS_LINUX
+ origin = "$ORIGIN";
+#else
+ origin = NULL;
+#endif
+
// BUG: Perl dumps its shared library in a strange place.
// This function returns `$ORIGIN/../../../CORE` which is not what we want to see.
// TODO: We WANT to see this: `$ORIGIN/../lib/perl5/xx.xx.xx/<arch>/CORE` not just the basename()
@@ -256,7 +254,7 @@ char *rpath_autodetect(const char *filename, FSTree *tree) {
// Get the shared library name we are going to look for in the tree
char *shared_library = strlist_item(libs_wanted, i);
- // Is the the shared library in the tree?
+ // Is the shared library in the tree?
char *match = NULL;
if ((match = dirname(strstr_array(tree->files, shared_library))) != NULL) {
// Begin generating the relative path string
@@ -283,12 +281,14 @@ char *rpath_autodetect(const char *filename, FSTree *tree) {
}
}
+#if OS_LINUX
// Some programs do not require local libraries provided by SPM (i.e. libc)
// Inject "likely" defaults here
if (strlist_count(libs) == 0) {
strlist_append(libs, "$ORIGIN/../lib");
strlist_append(libs, "$ORIGIN/../lib64");
}
+#endif
// Populate result string
result = join(libs->data, ":");
diff --git a/lib/shlib.c b/lib/shlib.c
index 7eed058..091d22e 100644
--- a/lib/shlib.c
+++ b/lib/shlib.c
@@ -1,7 +1,7 @@
#include "spm.h"
#include "shlib.h"
-char *shlib_deps_objdump(const char *_filename) {
+char *objdump(const char *_filename, char *_args) {
// do not expose this function
char *filename = NULL;
char *result = NULL;
@@ -21,7 +21,7 @@ char *shlib_deps_objdump(const char *_filename) {
}
strchrdel(filename, SHELL_INVALID);
- snprintf(cmd, sizeof(cmd), "%s %s '%s'", SPM_SHLIB_EXEC, SPM_SHLIB_EXEC_ARGS, filename);
+ snprintf(cmd, sizeof(cmd), "%s %s '%s'", SPM_SHLIB_EXEC, _args, filename);
shell(&proc, SHELL_OUTPUT, cmd);
if (proc->returncode != 0) {
@@ -36,6 +36,90 @@ char *shlib_deps_objdump(const char *_filename) {
return result;
}
+char *shlib_rpath(const char *filename) {
+ char **data = NULL;
+ char *raw_data = NULL;
+ char *result = NULL;
+
+ if (filename == NULL) {
+ spmerrno = EINVAL;
+ spmerrno_cause("filename was NULL");
+ return NULL;
+ }
+
+ if ((raw_data = objdump(filename, SPM_SHLIB_EXEC_ARGS)) == NULL) {
+ return NULL;
+ }
+
+ // Split output into individual lines
+ if ((data = split(raw_data, "\n")) == NULL) {
+ free(raw_data);
+ return NULL;
+ }
+
+ // Collapse all whitespace in each line
+ // i.e. " stuff things" -> "stuff things"
+ for (size_t i = 0; data[i] != NULL; i++) {
+ data[i] = normalize_space(data[i]);
+ }
+
+ for (size_t i = 0; data[i] != NULL; i++) {
+ char **field = NULL;
+ char reason[255] = {0,};
+
+#if OS_LINUX
+ // Extract the RPATH record (second field)
+ if (startswith(data[i], "RPATH")) {
+ if ((field = split(data[i], " ")) == NULL) {
+ break;
+ }
+
+ // record library path
+ result = strdup(field[1]);
+ split_free(field);
+ break;
+ }
+#elif OS_DARWIN
+ size_t offset_name = i + 2; // how many lines to look ahead after reaching LC_RPATH
+ size_t numLines;
+ for (numLines = 0; data[numLines] != NULL; numLines++); // get line count
+
+ // Find APPLE's equivalent to RPATH on Linux
+ if (startswith(data[i], "cmd LC_RPATH")) {
+ // Don't overrun the data buffer
+ if (offset_name > numLines || data[offset_name] == NULL) {
+ break;
+ }
+
+ // split on: "path /library/path"
+ if ((field = split(data[offset_name], " ")) == NULL) {
+ sprintf(reason, "'%s' produced unreadable output at offset %zu", SPM_SHLIB_EXEC, offset_name);
+ spmerrno = SPM_ERR_PARSE;
+ spmerrno_cause(reason);
+ break;
+ }
+
+ // verify it was actually "path ..."
+ if (strcmp(field[0], "path") != 0) {
+ sprintf(reason, "'%s' produced unexpected LC_RPATH format between lines %zu:%zu", SPM_SHLIB_EXEC, i, offset_name);
+ spmerrno = SPM_ERR_PARSE;
+ spmerrno_cause(reason);
+ break;
+ }
+
+ // record library path
+ result = strdup(field[1]);
+ split_free(field);
+ break;
+ }
+#endif
+ }
+
+ free(raw_data);
+ split_free(data);
+ return result;
+}
+
StrList *shlib_deps(const char *filename) {
char **data = NULL;
char *raw_data = NULL;
@@ -48,8 +132,7 @@ StrList *shlib_deps(const char *filename) {
}
// Get output from objdump
- // TODO: use preprocessor or another function to select the correct shlib_deps_*() in the future
- if ((raw_data = shlib_deps_objdump(filename)) == NULL) {
+ if ((raw_data = objdump(filename, SPM_SHLIB_EXEC_ARGS)) == NULL) {
return NULL;
}