int main(int argc, char **argv) { /* Parse our arguments: Options will be parsed until the first non-option is * found. Parsed arguments will manipulate the current environment to initial- * ize it for use with P^nMPI. If there are no additional non-options in our * arguments, argp_parse will print the usage message and exit immediatly, no * extra evaluation is required here. The index of the first non-option will * be stored in ind. */ int ind; argp_parse(&argp, argc, argv, ARGP_IN_ORDER, &ind, NULL); #ifdef __APPLE__ /* For apple systems, add libpnmpif to DYLD_INSERT_LIBRARIES, the apple ver- * sion of LD_PRELOAD. DYLD_FORCE_FLAT_NAMESPACE has to be set, to get all * symbols in the same namespace. Otherwise P^nMPI and libmpi won't see each * other and no preloading will happen. */ appendenv("DYLD_INSERT_LIBRARIES", PNMPI_LIBRARY_DIR "/" PNMPI_LIBRARY_NAME ".dylib"); setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", 1); #else /* For other systems (Linux and other UNIX platforms), add libpnmpif to * LD_PRELOAD to load P^nMPI in front of libmpi. */ appendenv("LD_PRELOAD", PNMPI_LIBRARY_DIR "/" PNMPI_LIBRARY_NAME ".so"); #endif /* Execute the utility. If the utility could be started, pnmpize will exit * here. In any other case, the following error processing will be called. */ if (execvp(argv[ind], argv + ind) < 0) { fprintf(stderr, "Could not execute %s: %s\n", argv[ind], strerror(errno)); return EXIT_FAILURE; } }
/** \brief Argument parser for argp. * * \note See argp parser documentation for detailed information about the * structure and functionality of function. */ static error_t parse_arguments(int key, char *arg, struct argp_state *state) { switch (key) { case 'c': setenv("PNMPI_CONF", arg, 1); break; case 'd': set_dbglevel(state, arg); break; case 'm': appendenv("PNMPI_LIB_PATH", arg, 1); break; case 'n': setenv("PNMPI_DBGNODE", arg, 1); break; case 'q': case 's': setenv("PNMPI_BE_SILENT", "1", 1); break; #ifdef ENABLE_FORTRAN case 'f': preload_library(PNMPI_FORTRAN_LIBRARY_NAME); pnmpi_library_loaded = 1; break; #endif /* If we have parsed all options, iterate through all non-options in argv. * If at there are no non-options in our arguments (argv), the user * specified no utility to call, so we'll print the argp usage here, which * will exit pnmpize immediately after printing the usage message. */ case ARGP_KEY_END: if (state->arg_num == 0) argp_usage(state); break; default: return ARGP_ERR_UNKNOWN; } return 0; }
/** * Preload a specific library. * * * @param library The library to be preloaded. */ static void preload_library(const char *library) { #ifdef __APPLE__ /* For apple systems, add the library to DYLD_INSERT_LIBRARIES, the macOS * version of LD_PRELOAD. DYLD_FORCE_FLAT_NAMESPACE has to be set, to get all * symbols in the same namespace. Otherwise P^nMPI and libmpi won't see each * other and no preloading will happen. */ char *lib = find_library(library); appendenv("DYLD_INSERT_LIBRARIES", lib, 0); setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", 1); free(lib); #else /* For other systems (Linux and other UNIX platforms), add the library to * LD_PRELOAD to load P^nMPI in front of libmpi. No path to the shared object, * but just the filename is required, as the dynamic loader searches in the * LD_LIBRARY_PATH for this file. */ appendenv("LD_LIBRARY_PATH", PNMPI_LIBRARY_PATH, 0); appendenv("LD_PRELOAD", library, 0); #endif }
/** \brief Search for a library in the search paths of the dynamic linker. * * \details This function searches for \p library in the search path of the * dynamic linker. Its use is to get the same behavior as for `LD_PRELOAD`, * that the library doesn't have to be at a fixed place. * * * \param library The library to be searched. * * \return If the library has been found, a pointer to a new allocated string * containing its path will be returned. Remember to free this buffer! * \return If the library could not be found in any path, the application will * be exited immediately with an error code. */ static char *find_library(const char *library) { /* As the DYLD_LIBRARY_PATH variable might not reach PnMPIze because of the * security features of mac OS, we'll set this variable with the contents of * PNMPI_PATH, if it doesn't exist yet. */ if (getenv("DYLD_LIBRARY_PATH") == NULL) { const char *tmp = getenv("PNMPI_PATH"); if (tmp != NULL) setenv("DYLD_LIBRARY_PATH", tmp, 0); } /* Generate the library search path, combined on first DYLD_LIBRARY_PATH and * then DYLD_FALLBACK_LIBRARY_PATH. If the latter is not defined in the * environment, it will be set by the default value of the mac OS dynamic * linker. */ if (!getenv("DYLD_FALLBACK_LIBRARY_PATH")) { const char *home = getenv("HOME"); size_t len = strlen(home) + 5 + sizeof(DEFAULT_FALLBACK_LIBRARY_PATH); char buffer[len]; snprintf(buffer, len, "%s/lib:%s", home, DEFAULT_FALLBACK_LIBRARY_PATH); setenv("DYLD_FALLBACK_LIBRARY_PATH", buffer, 0); } appendenv("DYLD_LIBRARY_PATH", getenv("DYLD_FALLBACK_LIBRARY_PATH"), 0); /* DYLD_LIBRARY_PATH is a colon separated list of paths to search for * libraries. Iterate over all of these paths now to find the searched one. */ char *path = strtok(getenv("DYLD_LIBRARY_PATH"), ":"); while (path) { /* Check if the searched library can be found in this path. If yes, * duplicate the buffer and return this string, so the callee can use this * path. */ size_t len = strlen(path) + strlen(library) + 2; char buffer[len]; snprintf(buffer, len, "%s/%s", path, library); if (access(buffer, F_OK) != -1) return strdup(buffer); /* Get the next path. */ path = strtok(NULL, ":"); } /* The searched library can't be found in any path. */ fprintf(stderr, "Could not find the PnMPI library.\n"); exit(EXIT_FAILURE); }