diff options
author | Joseph Hunkeler <jhunkeler@users.noreply.github.com> | 2020-05-07 06:11:13 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-07 06:11:13 -0400 |
commit | 26db5dff18a40b402d20a572953870aab549c5f2 (patch) | |
tree | 539d6a9800f41efad4ed50b1864aae1e677ccded /lib | |
parent | 6cc450d8ff714af09374f9bc07aea8bb05f74a5c (diff) | |
parent | de47b0d91a79651088e76d64dc4b032146203cca (diff) | |
download | spmc-26db5dff18a40b402d20a572953870aab549c5f2.tar.gz |
Merge pull request #33 from jhunkeler/install-name-tool
Install name tool (etc...)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CMakeLists.txt | 5 | ||||
-rw-r--r-- | lib/error_handler.c | 1 | ||||
-rw-r--r-- | lib/install.c | 1 | ||||
-rw-r--r-- | lib/internal_cmd.c | 9 | ||||
-rw-r--r-- | lib/rpath.c | 120 | ||||
-rw-r--r-- | lib/shlib.c | 91 |
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; } |