From e81c070ef0f68f9c1e8979cde20a26f622922198 Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Wed, 18 Feb 2015 10:12:49 -0800 Subject: [PATCH 1/9] dl framework: new dynamic loader framework Embedding libltdl without the use of Libtool bootstrapping has proven... difficult. Instead, create a new simple "dl" framework. It only provides 4 functions: - open a DSO (very similar to lt_dlopenadvise()) - lookup a symbol in a previously-opened DSO (very similar to lt_dlsym()) - close a previously-opened DSO (very similar to lt_dlclose()) - iterate over all files in a directory (very similar to ld_dlforeachfile()) There will be follow-on commits with a simple dlopen-based component (nowhere near as complete/functional as libltdl, but good enough for Linux and OS X), and a libltdl-based component for all other platforms. The intent is that the dlopen-based component can be built by default in almost all cases. But if libltdl is available, that component will be built. End result: we still get DSO-based functionality by default in (almost?) all cases. Without embedding libltdl. Which is what we want. --- README | 3 +- opal/mca/dl/Makefile.am | 36 ++++++ opal/mca/dl/base/Makefile.am | 17 +++ opal/mca/dl/base/base.h | 106 +++++++++++++++++ opal/mca/dl/base/dl_base_close.c | 25 ++++ opal/mca/dl/base/dl_base_fns.c | 68 +++++++++++ opal/mca/dl/base/dl_base_open.c | 54 +++++++++ opal/mca/dl/base/dl_base_select.c | 52 +++++++++ opal/mca/dl/configure.m4 | 77 +++++++++++++ opal/mca/dl/dl.h | 184 ++++++++++++++++++++++++++++++ 10 files changed, 621 insertions(+), 1 deletion(-) create mode 100644 opal/mca/dl/Makefile.am create mode 100644 opal/mca/dl/base/Makefile.am create mode 100644 opal/mca/dl/base/base.h create mode 100644 opal/mca/dl/base/dl_base_close.c create mode 100644 opal/mca/dl/base/dl_base_fns.c create mode 100644 opal/mca/dl/base/dl_base_open.c create mode 100644 opal/mca/dl/base/dl_base_select.c create mode 100644 opal/mca/dl/configure.m4 create mode 100644 opal/mca/dl/dl.h diff --git a/README b/README index f54e28a7409..811ef9f9b22 100644 --- a/README +++ b/README @@ -8,7 +8,7 @@ Copyright (c) 2004-2008 High Performance Computing Center Stuttgart, University of Stuttgart. All rights reserved. Copyright (c) 2004-2007 The Regents of the University of California. All rights reserved. -Copyright (c) 2006-2014 Cisco Systems, Inc. All rights reserved. +Copyright (c) 2006-2015 Cisco Systems, Inc. All rights reserved. Copyright (c) 2006-2011 Mellanox Technologies. All rights reserved. Copyright (c) 2006-2012 Oracle and/or its affiliates. All rights reserved. Copyright (c) 2007 Myricom, Inc. All rights reserved. @@ -1977,6 +1977,7 @@ backtrace - Debugging call stack backtrace support compress - Compression algorithms crs - Checkpoint and restart service db - Internal database support +dl - Dynamic loading library interface event - Event library (libevent) versioning support hwloc - Hardware locality (hwloc) versioning support if - OS IP interface support diff --git a/opal/mca/dl/Makefile.am b/opal/mca/dl/Makefile.am new file mode 100644 index 00000000000..f3b6011f817 --- /dev/null +++ b/opal/mca/dl/Makefile.am @@ -0,0 +1,36 @@ +# +# Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana +# University Research and Technology +# Corporation. All rights reserved. +# Copyright (c) 2010-2015 Cisco Systems, Inc. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +# main library setup +noinst_LTLIBRARIES = libmca_dl.la +libmca_dl_la_SOURCES = + +# local files +headers = dl.h +libmca_dl_la_SOURCES += $(headers) + +# Ensure that the man pages are rebuilt if the opal_config.h file +# changes; a "good enough" way to know if configure was run again (and +# therefore the release date or version may have changed) +$(nodist_man_MANS): $(top_builddir)/opal/include/opal_config.h + +# Conditionally install the header files +if WANT_INSTALL_HEADERS +opaldir = $(opalincludedir)/$(subdir) +nobase_opal_HEADERS = $(headers) +endif + +include base/Makefile.am + +distclean-local: + rm -f base/static-components.h + rm -f $(nodist_man_MANS) diff --git a/opal/mca/dl/base/Makefile.am b/opal/mca/dl/base/Makefile.am new file mode 100644 index 00000000000..7a6503167c1 --- /dev/null +++ b/opal/mca/dl/base/Makefile.am @@ -0,0 +1,17 @@ +# +# Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +headers += \ + base/base.h + +libmca_dl_la_SOURCES += \ + base/dl_base_open.c \ + base/dl_base_close.c \ + base/dl_base_select.c \ + base/dl_base_fns.c diff --git a/opal/mca/dl/base/base.h b/opal/mca/dl/base/base.h new file mode 100644 index 00000000000..0a0ad79dcf2 --- /dev/null +++ b/opal/mca/dl/base/base.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#ifndef OPAL_DL_BASE_H +#define OPAL_DL_BASE_H + +#include "opal_config.h" +#include "opal/mca/dl/dl.h" +#include "opal/util/opal_environ.h" +#include "opal/runtime/opal_cr.h" + +#include "opal/mca/base/base.h" + + +BEGIN_C_DECLS + +/** + * Globals + */ +OPAL_DECLSPEC extern mca_base_framework_t opal_dl_base_framework; +OPAL_DECLSPEC extern opal_dl_base_component_t +*opal_dl_base_selected_component; +OPAL_DECLSPEC extern opal_dl_base_module_t *opal_dl; + + +/** + * Initialize the DL MCA framework + * + * @retval OPAL_SUCCESS Upon success + * @retval OPAL_ERROR Upon failures + * + * This function is invoked during opal_init(); + */ +OPAL_DECLSPEC int opal_dl_base_open(mca_base_open_flag_t flags); + +/** + * Select an available component. + * + * @retval OPAL_SUCCESS Upon Success + * @retval OPAL_NOT_FOUND If no component can be selected + * @retval OPAL_ERROR Upon other failure + * + */ +OPAL_DECLSPEC int opal_dl_base_select(void); + +/** + * Finalize the DL MCA framework + * + * @retval OPAL_SUCCESS Upon success + * @retval OPAL_ERROR Upon failures + * + * This function is invoked during opal_finalize(); + */ +OPAL_DECLSPEC int opal_dl_base_close(void); + +/** + * Open a DSO + * + * (see opal_dl_base_module_open_ft_t in opal/mca/dl/dl.h for + * documentation of this function) + */ +OPAL_DECLSPEC int opal_dl_open(const char *fname, + bool use_ext, bool private_namespace, + opal_dl_handle_t **handle, char **err_msg); + +/** + * Lookup a symbol in a DSO + * + * (see opal_dl_base_module_lookup_ft_t in opal/mca/dl/dl.h for + * documentation of this function) + */ +OPAL_DECLSPEC int opal_dl_lookup(opal_dl_handle_t *handle, + const char *symbol, + void **ptr, char **err_msg); + +/** + * Close a DSO + * + * (see opal_dl_base_module_close_ft_t in opal/mca/dl/dl.h for + * documentation of this function) + */ +OPAL_DECLSPEC int opal_dl_close(opal_dl_handle_t *handle); + +/** + * Iterate over files in a path + * + * (see opal_dl_base_module_foreachfile_ft_t in opal/mca/dl/dl.h for + * documentation of this function) + */ +OPAL_DECLSPEC int opal_dl_foreachfile(const char *search_path, + int (*cb_func)(const char *filename, + void *context), + void *context); + +END_C_DECLS + +#endif /* OPAL_DL_BASE_H */ diff --git a/opal/mca/dl/base/dl_base_close.c b/opal/mca/dl/base/dl_base_close.c new file mode 100644 index 00000000000..3bf286ab443 --- /dev/null +++ b/opal/mca/dl/base/dl_base_close.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2004-2010 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" + +#include "opal/mca/mca.h" +#include "opal/mca/base/base.h" + +#include "opal/mca/dl/dl.h" +#include "opal/mca/dl/base/base.h" + + +int opal_dl_base_close(void) +{ + /* Close all available modules that are open */ + return mca_base_framework_components_close(&opal_dl_base_framework, NULL); +} diff --git a/opal/mca/dl/base/dl_base_fns.c b/opal/mca/dl/base/dl_base_fns.c new file mode 100644 index 00000000000..32b70111236 --- /dev/null +++ b/opal/mca/dl/base/dl_base_fns.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2004-2010 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +/** + * This file is a simple set of wrappers around the selected OPAL DL + * component (it's a compile-time framework with, at most, a single + * component; see dl.h for details). + */ + +#include "opal_config.h" + +#include "opal/include/opal/constants.h" + +#include "opal/mca/dl/base/base.h" + + +int opal_dl_open(const char *fname, + bool use_ext, bool private_namespace, + opal_dl_handle_t **handle, char **err_msg) +{ + *handle = NULL; + + if (NULL != opal_dl && NULL != opal_dl->open) { + return opal_dl->open(fname, use_ext, private_namespace, + handle, err_msg); + } + + return OPAL_ERR_NOT_SUPPORTED; +} + +int opal_dl_lookup(opal_dl_handle_t *handle, + const char *symbol, + void **ptr, char **err_msg) +{ + if (NULL != opal_dl && NULL != opal_dl->lookup) { + return opal_dl->lookup(handle, symbol, ptr, err_msg); + } + + return OPAL_ERR_NOT_SUPPORTED; +} + +int opal_dl_close(opal_dl_handle_t *handle) +{ + if (NULL != opal_dl && NULL != opal_dl->close) { + return opal_dl->close(handle); + } + + return OPAL_ERR_NOT_SUPPORTED; +} + +int opal_dl_foreachfile(const char *search_path, + int (*cb_func)(const char *filename, void *context), + void *context) +{ + if (NULL != opal_dl && NULL != opal_dl->foreachfile) { + return opal_dl->foreachfile(search_path, cb_func, context); + } + + return OPAL_ERR_NOT_SUPPORTED; +} diff --git a/opal/mca/dl/base/dl_base_open.c b/opal/mca/dl/base/dl_base_open.c new file mode 100644 index 00000000000..5e65cff9c0b --- /dev/null +++ b/opal/mca/dl/base/dl_base_open.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2004-2010 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2011-2013 Los Alamos National Security, LLC. + * All rights reserved. + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" + +#include "opal/mca/dl/base/base.h" + +#include "opal/mca/dl/base/static-components.h" + + +/* + * Globals + */ +opal_dl_base_module_t *opal_dl = NULL; +opal_dl_base_component_t *opal_dl_base_selected_component = NULL; + + +/* + * Function for finding and opening either all MCA components, + * or the one that was specifically requested via a MCA parameter. + * + * Note that we really don't need this function -- we could specify a + * NULL pointer in the framework declare and the base would do this + * exact same thing. However, we need to have at least some + * executable code in this file, or some linkers (cough cough OS X + * cough cough) may not actually link in this .o file. + */ +int opal_dl_base_open(mca_base_open_flag_t flags) +{ + /* Open up all available components */ + return mca_base_framework_components_open(&opal_dl_base_framework, flags); +} + +/* VERY IMPORTANT: This framework is static, and is opened before any + other dyanmic frameworks are opened (which makes sense, of course). + But we must mark this framework is NO_DSO so that the MCA framework + base doesn't try to open any dynamic components in this + framework. */ +MCA_BASE_FRAMEWORK_DECLARE(opal, dl, "Dynamic loader framework", + NULL /* register */, + opal_dl_base_open /* open */, + NULL /* close */, + mca_dl_base_static_components, + MCA_BASE_FRAMEWORK_FLAG_NO_DSO); diff --git a/opal/mca/dl/base/dl_base_select.c b/opal/mca/dl/base/dl_base_select.c new file mode 100644 index 00000000000..4abcccdbb0f --- /dev/null +++ b/opal/mca/dl/base/dl_base_select.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004-2010 The Trustees of Indiana University. + * All rights reserved. + * + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" + +#ifdef HAVE_UNISTD_H +#include "unistd.h" +#endif + +#include "opal/include/opal/constants.h" +#include "opal/util/output.h" +#include "opal/mca/mca.h" +#include "opal/mca/base/base.h" +#include "opal/mca/dl/dl.h" +#include "opal/mca/dl/base/base.h" + + +int opal_dl_base_select(void) +{ + int exit_status = OPAL_SUCCESS; + opal_dl_base_component_t *best_component = NULL; + opal_dl_base_module_t *best_module = NULL; + + /* + * Select the best component + */ + if (OPAL_SUCCESS != mca_base_select("dl", + opal_dl_base_framework.framework_output, + &opal_dl_base_framework.framework_components, + (mca_base_module_t **) &best_module, + (mca_base_component_t **) &best_component) ) { + /* This will only happen if no component was selected */ + exit_status = OPAL_ERROR; + goto cleanup; + } + + /* Save the winner */ + opal_dl_base_selected_component = best_component; + opal_dl = best_module; + + cleanup: + return exit_status; +} diff --git a/opal/mca/dl/configure.m4 b/opal/mca/dl/configure.m4 new file mode 100644 index 00000000000..a3e2d00595c --- /dev/null +++ b/opal/mca/dl/configure.m4 @@ -0,0 +1,77 @@ +dnl -*- shell-script -*- +dnl +dnl Copyright (c) 2010-2015 Cisco Systems, Inc. All rights reserved. +dnl $COPYRIGHT$ +dnl +dnl Additional copyrights may follow +dnl +dnl $HEADER$ +dnl + +dnl There will only be one component used in this framework, and it will +dnl be selected at configure time by priority. Components must set +dnl their priorities in their configure.m4 file. + +dnl We only want one winning component (vs. STOP_AT_FIRST_PRIORITY, +dnl which will allow all components of the same priority who succeed to +dnl win) +m4_define(MCA_opal_dl_CONFIGURE_MODE, STOP_AT_FIRST) + +AC_DEFUN([MCA_opal_dl_CONFIG],[ + OPAL_HAVE_DL_SUPPORT=0 + + # If --disable-dlopen was used, then have all the components fail + # (we still need to configure them all so that things like "make + # dist" work", but we just want the MCA system to (artificially) + # conclude that it can't build any of the components. + AS_IF([test "$enable_dlopen" = "no"], + [want_dl=0], [want_dl=1]) + + MCA_CONFIGURE_FRAMEWORK([opal], [dl], [$want_dl]) + + # If we found no suitable static dl component and dlopen support + # was not specifically disabled, this is an error. + AS_IF([test "$MCA_opal_dl_STATIC_COMPONENTS" = "" && \ + test "$enable_dlopen" != "no"], + [AC_MSG_WARN([Did not find a suitable static opal dl component]) + AC_MSG_WARN([You might need to install libltld (and its headers) or]) + AC_MSG_WARN([specify --disable-dlopen to configure.]) + AC_MSG_ERROR([Cannot continue])]) + + # If we have a winning component (which, per above, will only + # happen if --disable-dlopen was *not* specified), do some more + # logic. + AS_IF([test "$MCA_opal_dl_STATIC_COMPONENTS" != ""], + [ # We had a winner -- w00t! + + OPAL_HAVE_DL_SUPPORT=1 + # If we added any -L flags to ADD_LDFLAGS, then we (might) + # need to add those directories to LD_LIBRARY_PATH. + # Otherwise, if we try to AC RUN_IFELSE anything here in + # configure, it might die because it can't find the libraries + # we just linked against. + OPAL_VAR_SCOPE_PUSH([opal_dl_base_found_l opal_dl_base_token opal_dl_base_tmp opal_dl_base_dir]) + opal_dl_base_found_l=0 + eval "opal_dl_base_tmp=\$opal_dl_${opal_dl_winner}_ADD_LIBS" + for opal_dl_base_token in $opal_dl_base_tmp; do + case $opal_dl_base_token in + -l*) opal_dl_base_found_l=1 ;; + esac + done + AS_IF([test $opal_dl_base_found_l -eq 1], + [eval "opal_dl_base_tmp=\$opal_dl_${opal_dl_winner}_ADD_LDFLAGS" + for opal_dl_base_token in $opal_dl_base_tmp; do + case $opal_dl_base_token in + -L*) + opal_dl_base_dir=`echo $opal_dl_base_token | cut -c3-` + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$opal_dl_base_dir + AC_MSG_WARN([Adding to LD_LIBRARY_PATH: $opal_dl_base_dir]) + ;; + esac + done]) + OPAL_VAR_SCOPE_POP + ]) + + AC_DEFINE_UNQUOTED([OPAL_HAVE_DL_SUPPORT], [$OPAL_HAVE_DL_SUPPORT], + [Whether the OPAL DL framework is functional or not]) +]) diff --git a/opal/mca/dl/dl.h b/opal/mca/dl/dl.h new file mode 100644 index 00000000000..c79e9482aed --- /dev/null +++ b/opal/mca/dl/dl.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +/** + * @file + * + * Dynamic library framework + * + * General Description: + * + * This framework provides portable access to dlopen- and dlsym-like + * functionality, very similar to Libtool's libltdl. Indeed, one of + * the components in this framework will use libltdl, if it is + * present/available. However, on some common types systems where + * libltdl headers and libraries are *not* available, we can support + * plugins via this simple framework. + * + * This is a compile-time framework: a single component will be + * selected by the priority that its configure.m4 provides. All other + * components will be ignored (i.e., not built/not part of the + * installation). Meaning: the static_components of the dl framework + * will always contain 0 or 1 components. + * + * SIDENOTE: Open MPI used to embed libltdl. However, as of early + * 2015, this became problematic, for a variety of complex and + * uninteresting reasons (see the following if you care about the + * details: https://github.com/open-mpi/ompi/issues/311, + * http://debbugs.gnu.org/cgi/bugreport.cgi?bug=19370, + * https://github.com/open-mpi/ompi/pull/366, + * https://github.com/open-mpi/ompi/pull/390). That being said, we, + * as a developer community, still wanted to be able to natively use + * DSOs by default. A small/simple framework for DL functionality, + * along with a simple component that supports dlopen/dlsym on POSIX + * platforms and another component that natively uses libltdl seemed + * like a good solution. + */ + +#ifndef MCA_DLOPEN_H +#define MCA_DLOPEN_H + +#include "opal_config.h" + +#include "opal/mca/mca.h" +#include "opal/mca/base/base.h" + +BEGIN_C_DECLS + +/** + * Handle for an opened file + */ +struct opal_dl_handle_t; +typedef struct opal_dl_handle_t opal_dl_handle_t; + +/** + * Dynamically open the file specified. + * + * Arguments: + * fname = Base filename to open. If NULL, open this process. + * use_ext = If true, try various filename suffixes that are + * relevant on this platform (e.g., .so, .dll, .dylib). If + * false, just use exactly whatever was passed as fname. + * private = If true, open the file in a private namespace. + * Otherwise, open the file in a global namespace. + * handle = Upon successful open, a handle to the opened file will + * be returned. + * err_msg= if non-NULL and !=OPAL_SUCCESS is returned, will point to a + * string error message + * + * Returns: + * OPAL_SUCCESS on success, or OPAL_ERROR + * + * Space for the handle must be allocated by the module (it can be + * freed during the call to opal_dl_base_module_dlclose_fn_t). + * + * The err_msg points to an internal string and should not be altered + * or freed by the caller. The contents of the err_msg string may + * change after successive calls to opal_dl API calls. + */ +typedef int (*opal_dl_base_module_open_fn_t) + (const char *fname, bool use_ext, bool private_namespace, + opal_dl_handle_t **handle, char **err_msg); + +/** + * Lookup a symbol in an opened file. + * + * Arguments: + * handle = handle of a previously dynamically opened file + * symbol = name of the symbol to lookup + * ptr = if found, a pointer to the symbol. Otherwise, NULL. + * err_msg= if non-NULL and !=OPAL_SUCCESS is returned, will point to a + * string error message + * Returns: + * OPAL_SUCCESS on success, or OPAL_ERROR + * + * + * The err_msg points to an internal string and should not be altered + * or freed by the caller. The contents of the err_msg string may + * change after successive calls to opal_dl API calls. + */ +typedef int (*opal_dl_base_module_lookup_fn_t) + (opal_dl_handle_t *handle, const char *symbol, void **ptr, char **err_msg); + +/** + * Dynamically close a previously dynamically-opened file. + * + * Arguments: + * handle = handle of a previously dynamically opened file. + * Returns: + * OPAL_SUCCESS on success, or OPAL_ERROR + * + * This function should close the file and free and resources + * associated with it (e.g., whatever is cached on the handle). + */ +typedef int (*opal_dl_base_module_close_fn_t) + (opal_dl_handle_t *handle); + +/** + * Search through a path of directories, invoking a callback on each + * unique regular (non-Libtool) file basename found (e.g., will only + * be invoked once for the files "foo.la" and "foo.so", with the + * parameter "foo"). + * + * Arguments: + * path = OPAL_ENV_SEP-delimited list of directories + * cb_func= function to invoke on each filename found + * data = context for callback function + * Returns: + * OPAL_SUCESS on success, OPAL_ERR* otherwise + */ +typedef int (*opal_dl_base_module_foreachfile_fn_t) + (const char *search_path, + int (*cb_func)(const char *filename, void *context), + void *context); + +/** + * Structure for DL components. + */ +struct opal_dl_base_component_1_0_0_t { + /** MCA base component */ + mca_base_component_t base_version; + /** MCA base data */ + mca_base_component_data_t base_data; + + /** Default priority */ + int priority; +}; +typedef struct opal_dl_base_component_1_0_0_t opal_dl_base_component_1_0_0_t; +typedef struct opal_dl_base_component_1_0_0_t opal_dl_base_component_t; + +/** + * Structure for DL modules + */ +struct opal_dl_base_module_1_0_0_t { + mca_base_module_2_0_0_t super; + + /** Open / close */ + opal_dl_base_module_open_fn_t open; + opal_dl_base_module_close_fn_t close; + + /** Lookup a symbol */ + opal_dl_base_module_lookup_fn_t lookup; + + /** Iterate looking for files */ + opal_dl_base_module_foreachfile_fn_t foreachfile; +}; +typedef struct opal_dl_base_module_1_0_0_t opal_dl_base_module_1_0_0_t; +typedef struct opal_dl_base_module_1_0_0_t opal_dl_base_module_t; + +/** + * Macro for use in components that are of type DL + */ +#define OPAL_DL_BASE_VERSION_1_0_0 \ + MCA_BASE_VERSION_2_0_0, \ + "dl", 1, 0, 0 + +END_C_DECLS + +#endif /* OPAL_DL_H */ From 7d340c0c26bec976a35297f725a199d7543b9c55 Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Wed, 18 Feb 2015 10:23:59 -0800 Subject: [PATCH 2/9] dlopen: simple dl component based on POSIX dlopen Works on systems with dlopen (e.g., Linux and OS X). It requires dlfcn.h and libdl, which many systems have installed by default. --- opal/mca/dl/dlopen/Makefile.am | 23 ++ opal/mca/dl/dlopen/configure.m4 | 55 +++++ opal/mca/dl/dlopen/dl_dlopen.h | 40 ++++ opal/mca/dl/dlopen/dl_dlopen_component.c | 128 +++++++++++ opal/mca/dl/dlopen/dl_dlopen_module.c | 263 +++++++++++++++++++++++ 5 files changed, 509 insertions(+) create mode 100644 opal/mca/dl/dlopen/Makefile.am create mode 100644 opal/mca/dl/dlopen/configure.m4 create mode 100644 opal/mca/dl/dlopen/dl_dlopen.h create mode 100644 opal/mca/dl/dlopen/dl_dlopen_component.c create mode 100644 opal/mca/dl/dlopen/dl_dlopen_module.c diff --git a/opal/mca/dl/dlopen/Makefile.am b/opal/mca/dl/dlopen/Makefile.am new file mode 100644 index 00000000000..53d8bd4762c --- /dev/null +++ b/opal/mca/dl/dlopen/Makefile.am @@ -0,0 +1,23 @@ +# +# Copyright (c) 2004-2010 The Trustees of Indiana University. +# All rights reserved. +# Copyright (c) 2014-2015 Cisco Systems, Inc. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +sources = \ + dl_dlopen.h \ + dl_dlopen_component.c \ + dl_dlopen_module.c + +# This component will only ever be built statically -- never as a DSO. + +noinst_LTLIBRARIES = libmca_dl_dlopen.la + +libmca_dl_dlopen_la_SOURCES = $(sources) +libmca_dl_dlopen_la_LDFLAGS = -module -avoid-version +libmca_dl_dlopen_la_LIBS = $(opal_dl_dlopen_LIBS) diff --git a/opal/mca/dl/dlopen/configure.m4 b/opal/mca/dl/dlopen/configure.m4 new file mode 100644 index 00000000000..74b59a25d4d --- /dev/null +++ b/opal/mca/dl/dlopen/configure.m4 @@ -0,0 +1,55 @@ +# -*- shell-script -*- +# +# Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved. +# +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +AC_DEFUN([MCA_opal_dl_dlopen_PRIORITY], [80]) + +# +# Force this component to compile in static-only mode +# +AC_DEFUN([MCA_opal_dl_dlopen_COMPILE_MODE], [ + AC_MSG_CHECKING([for MCA component $2:$3 compile mode]) + $4="static" + AC_MSG_RESULT([$$4]) +]) + +# MCA_dl_dlopen_CONFIG([action-if-can-compile], +# [action-if-cant-compile]) +# ------------------------------------------------ +AC_DEFUN([MCA_opal_dl_dlopen_CONFIG],[ + AC_CONFIG_FILES([opal/mca/dl/dlopen/Makefile]) + + dnl This is effectively a back-door for Open MPI developers to + dnl force the use of the libltdl dl component. + AC_ARG_ENABLE([dl-dlopen], + [AS_HELP_STRING([--disable-dl-dlopen], + [Disable the "dlopen" DL component (and probably force the use of the "libltdl" DL component). This option should really only be used by Open MPI developers. You are probably actually looking for the "--disable-dlopen" option, which disables all dlopen-like functionality from Open MPI.]) + ]) + + opal_dl_dlopen_happy=no + AS_IF([test "$enable_dl_dlopen" != "no"], + [OPAL_CHECK_PACKAGE([opal_dl_dlopen], + [dlfcn.h], + [dl], + [dlopen], + [], + [], + [], + [opal_dl_dlopen_happy=yes], + [opal_dl_dlopen_happy=no]) + ]) + + AS_IF([test "$opal_dl_dlopen_happy" = "yes"], + [opal_dl_dlopen_ADD_LIBS=$opal_dl_dlopen_LIBS + $1], + [$2]) + + AC_SUBST(opal_dl_dlopen_LIBS) +]) diff --git a/opal/mca/dl/dlopen/dl_dlopen.h b/opal/mca/dl/dlopen/dl_dlopen.h new file mode 100644 index 00000000000..aa84903117b --- /dev/null +++ b/opal/mca/dl/dlopen/dl_dlopen.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#ifndef OPAL_DL_DLOPEN +#define OPAL_DL_DLOPEN + +#include "opal_config.h" + +#include "opal/mca/dl/dl.h" + +OPAL_DECLSPEC extern opal_dl_base_module_t opal_dl_dlopen_module; + +/* + * Dynamic library handles generated by this component. + * + * If we're debugging, keep a copy of the name of the file we've opened. + */ +struct opal_dl_handle_t { + void *dlopen_handle; +#if OPAL_ENABLE_DEBUG + void *filename; +#endif +}; + +typedef struct { + opal_dl_base_component_t base; + + char *filename_suffixes_mca_storage; + char **filename_suffixes; +} opal_dl_dlopen_component_t; + +OPAL_DECLSPEC extern opal_dl_dlopen_component_t mca_dl_dlopen_component; + +#endif /* OPAL_DL_DLOPEN */ diff --git a/opal/mca/dl/dlopen/dl_dlopen_component.c b/opal/mca/dl/dlopen/dl_dlopen_component.c new file mode 100644 index 00000000000..c7140c3a45b --- /dev/null +++ b/opal/mca/dl/dlopen/dl_dlopen_component.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" + +#include "opal/constants.h" +#include "opal/mca/dl/dl.h" +#include "opal/util/argv.h" + +#include "dl_dlopen.h" + + +/* + * Public string showing the sysinfo ompi_linux component version number + */ +const char *opal_dl_dlopen_component_version_string = + "OPAL dl dlopen MCA component version " OPAL_VERSION; + + +/* + * Local functions + */ +static int dlopen_component_register(void); +static int dlopen_component_open(void); +static int dlopen_component_close(void); +static int dlopen_component_query(mca_base_module_t **module, int *priority); + +/* + * Instantiate the public struct with all of our public information + * and pointers to our public functions in it + */ + +opal_dl_dlopen_component_t mca_dl_dlopen_component = { + + /* Fill in the mca_dl_base_component_t */ + .base = { + + /* First, the mca_component_t struct containing meta information + about the component itself */ + .base_version = { + OPAL_DL_BASE_VERSION_1_0_0, + + /* Component name and version */ + "dlopen", + OPAL_MAJOR_VERSION, + OPAL_MINOR_VERSION, + OPAL_RELEASE_VERSION, + + /* Component functions */ + .mca_register_component_params = dlopen_component_register, + .mca_open_component = dlopen_component_open, + .mca_close_component = dlopen_component_close, + .mca_query_component = dlopen_component_query, + }, + + .base_data = { + /* The component is checkpoint ready */ + MCA_BASE_METADATA_PARAM_CHECKPOINT + }, + + /* The dl framework members */ + .priority = 80 + }, + + /* Now fill in the dlopen component-specific members */ + .filename_suffixes_mca_storage = ".so,.dylib,.dll,.sl", + .filename_suffixes = NULL +}; + + +static int dlopen_component_register(void) +{ + int ret; + + ret = + mca_base_component_var_register(&mca_dl_dlopen_component.base.base_version, + "filename_suffixes", + "Comma-delimited list of filename suffixes that the dlopen component will try", + MCA_BASE_VAR_TYPE_STRING, + NULL, + 0, + MCA_BASE_VAR_FLAG_SETTABLE, + OPAL_INFO_LVL_5, + MCA_BASE_VAR_SCOPE_LOCAL, + &mca_dl_dlopen_component.filename_suffixes_mca_storage); + if (ret < 0) { + return ret; + } + mca_dl_dlopen_component.filename_suffixes = + opal_argv_split(mca_dl_dlopen_component.filename_suffixes_mca_storage, + ','); + + return OPAL_SUCCESS; +} + +static int dlopen_component_open(void) +{ + return OPAL_SUCCESS; +} + + +static int dlopen_component_close(void) +{ + if (NULL != mca_dl_dlopen_component.filename_suffixes) { + opal_argv_free(mca_dl_dlopen_component.filename_suffixes); + mca_dl_dlopen_component.filename_suffixes = NULL; + } + + return OPAL_SUCCESS; +} + + +static int dlopen_component_query(mca_base_module_t **module, int *priority) +{ + /* The priority value is somewhat meaningless here; by + opal/mca/dl/configure.m4, there's at most one component + available. */ + *priority = mca_dl_dlopen_component.base.priority; + *module = &opal_dl_dlopen_module.super; + + return OPAL_SUCCESS; +} diff --git a/opal/mca/dl/dlopen/dl_dlopen_module.c b/opal/mca/dl/dlopen/dl_dlopen_module.c new file mode 100644 index 00000000000..5eb1cb56842 --- /dev/null +++ b/opal/mca/dl/dlopen/dl_dlopen_module.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" + +#include +#include +#include +#include +#include +#include + +#include "opal/constants.h" +#include "opal/mca/dl/dl.h" +#include "opal/util/argv.h" + +#include "dl_dlopen.h" + + +/* + * Trivial helper function to avoid replicating code + */ +static void do_dlopen(const char *fname, int flags, + void **handle, char **err_msg) +{ + assert(fname); + assert(handle); + + *handle = dlopen(fname, flags); + + if (NULL != err_msg) { + if (NULL != *handle) { + *err_msg = NULL; + } else { + *err_msg = dlerror(); + } + } +} + + +static int dlopen_open(const char *fname, bool use_ext, bool private_namespace, + opal_dl_handle_t **handle, char **err_msg) +{ + assert(fname); + assert(handle); + + *handle = NULL; + + /* Setup the dlopen flags */ + int flags = RTLD_LAZY; + if (private_namespace) { + flags |= RTLD_LOCAL; + } else { + flags |= RTLD_GLOBAL; + } + + /* If the caller wants to use filename extensions, loop through + them */ + void *local_handle = NULL; + if (use_ext) { + int i; + char *ext; + + for (i = 0, ext = mca_dl_dlopen_component.filename_suffixes[i]; + NULL != ext; + ext = mca_dl_dlopen_component.filename_suffixes[++i]) { + char *name; + + asprintf(&name, "%s%s", fname, ext); + if (NULL == name) { + return OPAL_ERR_IN_ERRNO; + } + + /* Does the file exist? */ + struct stat buf; + if (stat(name, &buf) < 0) { + free(name); + if (NULL != err_msg) { + *err_msg = "File not found"; + } + continue; + } + + /* Yes, the file exists -- try to dlopen it. If we can't + dlopen it, bail. */ + do_dlopen(name, flags, &local_handle, err_msg); + free(name); + break; + } + } + + /* Otherwise, the caller does not want to use filename extensions, + so just use the single filename that the caller provided */ + else { + do_dlopen(fname, flags, &local_handle, err_msg); + } + + if (NULL != local_handle) { + *handle = calloc(1, sizeof(opal_dl_handle_t)); + (*handle)->dlopen_handle = local_handle; + +#if OPAL_ENABLE_DEBUG + (*handle)->filename = strdup(fname); +#endif + } + return (NULL != local_handle) ? OPAL_SUCCESS : OPAL_ERROR; +} + + +static int dlopen_lookup(opal_dl_handle_t *handle, const char *symbol, + void **ptr, char **err_msg) +{ + assert(handle); + assert(handle->dlopen_handle); + assert(symbol); + assert(ptr); + + *ptr = dlsym(handle->dlopen_handle, symbol); + if (NULL != *ptr) { + return OPAL_SUCCESS; + } + + if (NULL != err_msg) { + *err_msg = dlerror(); + } + return OPAL_ERROR; +} + + +static int dlopen_close(opal_dl_handle_t *handle) +{ + assert(handle); + + int ret; + ret = dlclose(handle->dlopen_handle); + +#if OPAL_ENABLE_DEBUG + free(handle->filename); +#endif + free(handle); + + return ret; +} + +/* + * Scan all the files in a directory (or path) and invoke a callback + * on each one. + */ +static int dlopen_foreachfile(const char *search_path, + int (*func)(const char *filename, void *data), + void *data) +{ + int ret; + DIR *dp = NULL; + char **dirs = NULL; + char **good_files = NULL; + + dirs = opal_argv_split(search_path, OPAL_ENV_SEP); + for (int i = 0; NULL != dirs[i]; ++i) { + + dp = opendir(dirs[i]); + if (NULL == dp) { + return OPAL_ERR_IN_ERRNO; + } + + struct dirent *de; + while (NULL != (de = readdir(dp))) { + + /* Make the absolute path name */ + char *abs_name = NULL; + asprintf(&abs_name, "%s/%s", dirs[i], de->d_name); + if (NULL == abs_name) { + ret = OPAL_ERR_IN_ERRNO; + goto error; + } + + /* Stat the file */ + struct stat buf; + if (stat(abs_name, &buf) < 0) { + free(abs_name); + ret = OPAL_ERR_IN_ERRNO; + goto error; + } + + /* Skip if not a file */ + if (!S_ISREG(buf.st_mode)) { + free(abs_name); + continue; + } + + /* Find the suffix */ + char *ptr = strrchr(abs_name, '.'); + if (NULL != ptr) { + + /* Skip libtool files */ + if (strcmp(ptr, ".la") == 0 || + strcmp(ptr, ".lo") == 0) { + continue; + } + + *ptr = '\0'; + } + + /* Have we already found this file? Or already found a + file with the same basename (but different suffix)? */ + if (NULL != good_files) { + for (int j = 0; NULL != good_files[j]; ++j) { + if (strcmp(good_files[j], abs_name) == 0) { + free(abs_name); + continue; + } + } + } + + opal_argv_append_nosize(&good_files, abs_name); + free(abs_name); + } + } + closedir(dp); + dp = NULL; + + /* Invoke the callback on all the found files */ + if (NULL != good_files) { + for (int i = 0; NULL != good_files[i]; ++i) { + ret = func(good_files[i], data); + if (OPAL_SUCCESS != ret) { + goto error; + } + } + } + + ret = OPAL_SUCCESS; + + error: + if (NULL != dp) { + closedir(dp); + } + if (NULL != dirs) { + opal_argv_free(dirs); + } + if (NULL != good_files) { + opal_argv_free(good_files); + } + + return ret; +} + + +/* + * Module definition + */ +opal_dl_base_module_t opal_dl_dlopen_module = { + .open = dlopen_open, + .lookup = dlopen_lookup, + .close = dlopen_close, + .foreachfile = dlopen_foreachfile +}; From 39364d315c6070e3e4349c599b9b12ffb840d249 Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Wed, 18 Feb 2015 10:17:51 -0800 Subject: [PATCH 3/9] libltdl: dl component based on libltdl Works on any system that libltdl supports and has ltdl.h and libltdl available. --- opal/mca/dl/libltdl/Makefile.am | 26 ++++ opal/mca/dl/libltdl/configure.m4 | 123 ++++++++++++++++ opal/mca/dl/libltdl/dl_libltdl.h | 50 +++++++ opal/mca/dl/libltdl/dl_libltdl_component.c | 155 +++++++++++++++++++++ opal/mca/dl/libltdl/dl_libltdl_module.c | 128 +++++++++++++++++ 5 files changed, 482 insertions(+) create mode 100644 opal/mca/dl/libltdl/Makefile.am create mode 100644 opal/mca/dl/libltdl/configure.m4 create mode 100644 opal/mca/dl/libltdl/dl_libltdl.h create mode 100644 opal/mca/dl/libltdl/dl_libltdl_component.c create mode 100644 opal/mca/dl/libltdl/dl_libltdl_module.c diff --git a/opal/mca/dl/libltdl/Makefile.am b/opal/mca/dl/libltdl/Makefile.am new file mode 100644 index 00000000000..d16d373d30a --- /dev/null +++ b/opal/mca/dl/libltdl/Makefile.am @@ -0,0 +1,26 @@ +# +# Copyright (c) 2004-2010 The Trustees of Indiana University. +# All rights reserved. +# Copyright (c) 2014-2015 Cisco Systems, Inc. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +sources = \ + dl_libltdl.h \ + dl_libltdl_component.c \ + dl_libltdl_module.c + +# This component will only ever be built statically -- never as a DSO. + +noinst_LTLIBRARIES = libmca_dl_libltdl.la + +libmca_dl_libltdl_la_SOURCES = $(sources) +libmca_dl_libltdl_la_CPPFLAGS = $(opal_dl_libltdl_CPPFLAGS) +libmca_dl_libltdl_la_LDFLAGS = \ + $(opal_dl_libltdl_LDFLAGS) \ + -module -avoid-version +libmca_dl_libltdl_la_LIBS = $(opal_dl_libltdl_LIBS) diff --git a/opal/mca/dl/libltdl/configure.m4 b/opal/mca/dl/libltdl/configure.m4 new file mode 100644 index 00000000000..1d9777215c4 --- /dev/null +++ b/opal/mca/dl/libltdl/configure.m4 @@ -0,0 +1,123 @@ +# -*- shell-script -*- +# +# Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved. +# +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +AC_DEFUN([MCA_opal_dl_libltdl_PRIORITY], [50]) + +# +# Force this component to compile in static-only mode +# +AC_DEFUN([MCA_opal_dl_libltdl_COMPILE_MODE], [ + AC_MSG_CHECKING([for MCA component $2:$3 compile mode]) + $4="static" + AC_MSG_RESULT([$$4]) +]) + +# MCA_event_external_POST_CONFIG() +# --------------------------------- +AC_DEFUN([MCA_opal_dl_libltdl_POST_CONFIG],[ + # If we won, then do all the rest of the setup + AS_IF([test "$1" = "1"], + [ + # Add some stuff to CPPFLAGS so that the rest of the source + # tree can be built + LDFLAGS="$LDFLAGS $opal_dl_libltdl_ADD_LDFLAGS" + LIBS="$LIBS $opal_dl_libltdl_ADD_LIBS" + ]) +])dnl + +# MCA_dl_libltdl_CONFIG([action-if-can-compile], +# [action-if-cant-compile]) +# ------------------------------------------------ +AC_DEFUN([MCA_opal_dl_libltdl_CONFIG],[ + OPAL_VAR_SCOPE_PUSH([CPPFLAGS_save LDFLAGS_save LIBS_save]) + AC_CONFIG_FILES([opal/mca/dl/libltdl/Makefile]) + + # Add --with options + AC_ARG_WITH([libltdl], + [AC_HELP_STRING([--with-libltdl(=DIR)], + [Build libltdl support, optionally adding DIR/include, DIR/lib, and DIR/lib64 to the search path for headers and libraries])]) + AC_ARG_WITH([libltdl-libdir], + [AC_HELP_STRING([--with-libltdl-libdir=DIR], + [Search for libltdl libraries in DIR])]) + + # Sanity check the --with values + OPAL_CHECK_WITHDIR([libltdl], [$with_libltdl], + [include/ltdl.h]) + OPAL_CHECK_WITHDIR([libltdl-libdir], [$with_libltdl_libdir], + [libltdl.*]) + + # Defaults + opal_check_libltdl_dir_msg="compiler default" + opal_check_libltdl_libdir_msg="linker default" + + # Save directory names if supplied + AS_IF([test ! -z "$with_libltdl" && test "$with_libltdl" != "yes"], + [opal_check_libltdl_dir=$with_libltdl + opal_check_libltdl_dir_msg="$opal_check_libltdl_dir (from --with-libltdl)"]) + AS_IF([test ! -z "$with_libltdl_libdir" && test "$with_libltdl_libdir" != "yes"], + [opal_check_libltdl_libdir=$with_libltdl_libdir + opal_check_libltdl_libdir_msg="$opal_check_libltdl_libdir (from --with-libltdl-libdir)"]) + + opal_dl_libltdl_happy=no + AS_IF([test "$with_libltdl" != "no"], + [AC_MSG_CHECKING([for libltdl dir]) + AC_MSG_RESULT([$opal_check_libltdl_dir_msg]) + AC_MSG_CHECKING([for libltdl library dir]) + AC_MSG_RESULT([$opal_check_libltdl_libdir_msg]) + + OPAL_CHECK_PACKAGE([opal_dl_libltdl], + [ltdl.h], + [ltdl], + [lt_dlopen], + [], + [$opal_check_libltdl_dir], + [$opal_check_libltdl_libdir], + [opal_dl_libltdl_happy=yes], + [opal_dl_libltdl_happy=no]) + ]) + + # If we have libltdl, do we have lt_dladvise? + opal_dl_libltdl_have_lt_dladvise=0 + AS_IF([test "$opal_dl_libltdl_happy" = "yes"], + [CPPFLAGS_save=$CPPFLAGS + LDFLAGS_save=$LDFLAGS + LIBS_save=$LIBS + + CPPFLAGS="$opal_dl_libltdl_CPPFLAGS $CPPFLAGS" + LDFLAGS="$opal_dl_libltdl_LDFLAGS $LDFLAGS" + LIBS="$opal_dl_libltdl_LIBS $LIBS" + AC_CHECK_FUNC([lt_dladvise_init], + [opal_dl_libltdl_have_lt_dladvise=1]) + CPPFLAGS=$CPPFLAGS_save + LDFLAGS=$LDFLAGS_save + LIBS=$LIBS_save + ]) + AC_DEFINE_UNQUOTED(OPAL_DL_LIBLTDL_HAVE_LT_DLADVISE, + [$opal_dl_libltdl_have_lt_dladvise], + [Whether we have lt_dladvise or not]) + + AS_IF([test "$opal_dl_libltdl_happy" = "yes"], + [opal_dl_libltdl_ADD_CPPFLAGS=$opal_dl_libltdl_CPPFLAGS + opal_dl_libltdl_ADD_LDFLAGS=$opal_dl_libltdl_LDFLAGS + opal_dl_libltdl_ADD_LIBS=$opal_dl_libltdl_LIBS + $1], + [AS_IF([test ! -z "$with_libltdl" && \ + test "$with_libltdl" != "no"], + [AC_MSG_WARN([Libltdl support requested (via --with-libltdl) but not found.]) + AC_MSG_ERROR([Cannot continue.])]) + $2]) + + AC_SUBST(opal_dl_libltdl_CPPFLAGS) + AC_SUBST(opal_dl_libltdl_LDFLAGS) + AC_SUBST(opal_dl_libltdl_LIBS) + + OPAL_VAR_SCOPE_POP +]) diff --git a/opal/mca/dl/libltdl/dl_libltdl.h b/opal/mca/dl/libltdl/dl_libltdl.h new file mode 100644 index 00000000000..c5b5b16788f --- /dev/null +++ b/opal/mca/dl/libltdl/dl_libltdl.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#ifndef OPAL_DL_LIBLTDL +#define OPAL_DL_LIBLTDL + +#include "opal_config.h" + +#include "opal/mca/dl/dl.h" + +#include + + +OPAL_DECLSPEC extern opal_dl_base_module_t opal_dl_libltdl_module; + +/* + * Dynamic library handles generated by this component. + * + * If we're debugging, keep a copy of the name of the file we've opened. + */ +struct opal_dl_handle_t { + lt_dlhandle ltdl_handle; +#if OPAL_ENABLE_DEBUG + char *filename; +#endif +}; + +typedef struct { + opal_dl_base_component_t base; + +#if OPAL_DL_LIBLTDL_HAVE_LT_DLADVISE + /* If the version of libltdl that we are compiling against has + lt_dladvise, use it to support opening DSOs in a variety of + modes. */ + lt_dladvise advise_private_noext; + lt_dladvise advise_private_ext; + lt_dladvise advise_public_noext; + lt_dladvise advise_public_ext; +#endif +} opal_dl_libltdl_component_t; + +OPAL_DECLSPEC extern opal_dl_libltdl_component_t mca_dl_libltdl_component; + +#endif /* OPAL_DL_LIBLTDL */ diff --git a/opal/mca/dl/libltdl/dl_libltdl_component.c b/opal/mca/dl/libltdl/dl_libltdl_component.c new file mode 100644 index 00000000000..e11c051b64d --- /dev/null +++ b/opal/mca/dl/libltdl/dl_libltdl_component.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" + +#include "opal/constants.h" +#include "opal/mca/dl/dl.h" +#include "opal/mca/base/mca_base_var.h" +#include "opal/util/argv.h" + +#include "dl_libltdl.h" + + +/* + * Public string showing the sysinfo ompi_linux component version number + */ +const char *opal_dl_libltdl_component_version_string = + "OPAL dl libltdl MCA component version " OPAL_VERSION; + + +/* + * Local functions + */ +static int libltdl_component_register(void); +static int libltdl_component_open(void); +static int libltdl_component_close(void); +static int libltdl_component_query(mca_base_module_t **module, int *priority); + +/* + * Instantiate the public struct with all of our public information + * and pointers to our public functions in it + */ + +opal_dl_libltdl_component_t mca_dl_libltdl_component = { + + /* Fill in the mca_dl_base_component_t */ + .base = { + + /* First, the mca_component_t struct containing meta information + about the component itself */ + .base_version = { + OPAL_DL_BASE_VERSION_1_0_0, + + /* Component name and version */ + "libltdl", + OPAL_MAJOR_VERSION, + OPAL_MINOR_VERSION, + OPAL_RELEASE_VERSION, + + /* Component functions */ + .mca_register_component_params = libltdl_component_register, + .mca_open_component = libltdl_component_open, + .mca_close_component = libltdl_component_close, + .mca_query_component = libltdl_component_query, + }, + + .base_data = { + /* The component is checkpoint ready */ + MCA_BASE_METADATA_PARAM_CHECKPOINT + }, + + /* The dl framework members */ + .priority = 50 + } + + /* Now fill in the libltdl component-specific members */ +}; + + +static int libltdl_component_register(void) +{ + /* Register an info param indicating whether we have lt_dladvise + support or not */ + bool supported = OPAL_INT_TO_BOOL(OPAL_DL_LIBLTDL_HAVE_LT_DLADVISE); + mca_base_component_var_register(&mca_dl_libltdl_component.base.base_version, + "have_lt_dladvise", + "Whether the version of libltdl that this component is built against supports lt_dladvise functionality or not", + MCA_BASE_VAR_TYPE_BOOL, + NULL, + 0, + MCA_BASE_VAR_FLAG_DEFAULT_ONLY, + OPAL_INFO_LVL_7, + MCA_BASE_VAR_SCOPE_CONSTANT, + &supported); + + return OPAL_SUCCESS; +} + +static int libltdl_component_open(void) +{ + if (lt_dlinit()) { + return OPAL_ERROR; + } + +#if OPAL_DL_LIBLTDL_HAVE_LT_DLADVISE + opal_dl_libltdl_component_t *c = &mca_dl_libltdl_component; + + if (lt_dladvise_init(&c->advise_private_noext)) { + return OPAL_ERR_OUT_OF_RESOURCE; + } + + if (lt_dladvise_init(&c->advise_private_ext) || + lt_dladvise_ext(&c->advise_private_ext)) { + return OPAL_ERR_OUT_OF_RESOURCE; + } + + if (lt_dladvise_init(&c->advise_public_noext) || + lt_dladvise_global(&c->advise_public_noext)) { + return OPAL_ERR_OUT_OF_RESOURCE; + } + + if (lt_dladvise_init(&c->advise_public_ext) || + lt_dladvise_global(&c->advise_public_ext) || + lt_dladvise_ext(&c->advise_public_ext)) { + return OPAL_ERR_OUT_OF_RESOURCE; + } +#endif + + return OPAL_SUCCESS; +} + + +static int libltdl_component_close(void) +{ +#if OPAL_DL_LIBLTDL_HAVE_LT_DLADVISE + opal_dl_libltdl_component_t *c = &mca_dl_libltdl_component; + + lt_dladvise_destroy(&c->advise_private_noext); + lt_dladvise_destroy(&c->advise_private_ext); + lt_dladvise_destroy(&c->advise_public_noext); + lt_dladvise_destroy(&c->advise_public_ext); +#endif + + lt_dlexit(); + + return OPAL_SUCCESS; +} + + +static int libltdl_component_query(mca_base_module_t **module, int *priority) +{ + /* The priority value is somewhat meaningless here; by + opal/mca/dl/configure.m4, there's at most one component + available. */ + *priority = mca_dl_libltdl_component.base.priority; + *module = &opal_dl_libltdl_module.super; + + return OPAL_SUCCESS; +} diff --git a/opal/mca/dl/libltdl/dl_libltdl_module.c b/opal/mca/dl/libltdl/dl_libltdl_module.c new file mode 100644 index 00000000000..ce853ac6c49 --- /dev/null +++ b/opal/mca/dl/libltdl/dl_libltdl_module.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" + +#include "opal/constants.h" +#include "opal/mca/dl/dl.h" + +#include "dl_libltdl.h" + + +static int libltdl_open(const char *fname, bool use_ext, bool private_namespace, + opal_dl_handle_t **handle, char **err_msg) +{ + assert(fname); + assert(handle); + + *handle = NULL; + if (NULL != err_msg) { + *err_msg = NULL; + } + + lt_dlhandle local_handle; + +#if OPAL_DL_LIBLTDL_HAVE_LT_DLADVISE + opal_dl_libltdl_component_t *c = &mca_dl_libltdl_component; + + if (use_ext && private_namespace) { + local_handle = lt_dlopenadvise(fname, c->advise_private_ext); + } else if (use_ext && !private_namespace) { + local_handle = lt_dlopenadvise(fname, c->advise_public_ext); + } else if (!use_ext && private_namespace) { + local_handle = lt_dlopenadvise(fname, c->advise_private_noext); + } else if (!use_ext && !private_namespace) { + local_handle = lt_dlopenadvise(fname, c->advise_public_noext); + } +#else + if (use_ext) { + local_handle = lt_dlopenext(fname); + } else { + local_handle = lt_dlopen(fname); + } +#endif + + if (NULL != local_handle) { + *handle = calloc(1, sizeof(opal_dl_handle_t)); + (*handle)->ltdl_handle = local_handle; + +#if OPAL_ENABLE_DEBUG + (*handle)->filename = strdup(fname); +#endif + + return OPAL_SUCCESS; + } + + if (NULL != err_msg) { + *err_msg = (char*) lt_dlerror(); + } + return OPAL_ERROR; +} + + +static int libltdl_lookup(opal_dl_handle_t *handle, const char *symbol, + void **ptr, char **err_msg) +{ + assert(handle); + assert(handle->ltdl_handle); + assert(symbol); + assert(ptr); + + if (NULL != err_msg) { + *err_msg = NULL; + } + + *ptr = lt_dlsym(handle->ltdl_handle, symbol); + if (NULL != *ptr) { + return OPAL_SUCCESS; + } + + if (NULL != err_msg) { + *err_msg = (char*) lt_dlerror(); + } + return OPAL_ERROR; +} + + +static int libltdl_close(opal_dl_handle_t *handle) +{ + assert(handle); + + int ret; + ret = lt_dlclose(handle->ltdl_handle); + +#if OPAL_ENABLE_DEBUG + free(handle->filename); +#endif + free(handle); + + return ret; +} + +static int libltdl_foreachfile(const char *search_path, + int (*func)(const char *filename, void *data), + void *data) +{ + assert(search_path); + assert(func); + + int ret = lt_dlforeachfile(search_path, func, data); + return (0 == ret) ? OPAL_SUCCESS : OPAL_ERROR; +} + + +/* + * Module definition + */ +opal_dl_base_module_t opal_dl_libltdl_module = { + .open = libltdl_open, + .lookup = libltdl_lookup, + .close = libltdl_close, + .foreachfile = libltdl_foreachfile +}; From a9d86129c6a4f0843f4e405b6d2d3a9e0c8e7c20 Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Wed, 18 Feb 2015 10:24:10 -0800 Subject: [PATCH 4/9] mca base: convert to opal_dl interface --- opal/mca/base/mca_base_component_find.c | 110 ++++++++---------- opal/mca/base/mca_base_component_repository.c | 97 +++++++-------- opal/mca/base/mca_base_component_repository.h | 34 +----- 3 files changed, 92 insertions(+), 149 deletions(-) diff --git a/opal/mca/base/mca_base_component_find.c b/opal/mca/base/mca_base_component_find.c index 19f0961fb01..a1e7f1b928d 100644 --- a/opal/mca/base/mca_base_component_find.c +++ b/opal/mca/base/mca_base_component_find.c @@ -10,7 +10,7 @@ * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. - * Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2008-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. @@ -43,14 +43,6 @@ #include #endif -#if OPAL_WANT_LIBLTDL - #if OPAL_LIBLTDL_INTERNAL - #include "opal/libltdl/ltdl.h" - #else - #include "ltdl.h" - #endif -#endif - #include "opal/mca/installdirs/installdirs.h" #include "opal/util/opal_environ.h" #include "opal/util/output.h" @@ -61,9 +53,10 @@ #include "opal/mca/base/base.h" #include "opal/mca/base/mca_base_component_repository.h" #include "opal/constants.h" +#include "opal/mca/dl/base/base.h" -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT /* * Private types; only necessary when we're dlopening components. */ @@ -98,20 +91,17 @@ typedef struct dependency_item_t dependency_item_t; static OBJ_CLASS_INSTANCE(dependency_item_t, opal_list_item_t, NULL, NULL); -#if OPAL_HAVE_LTDL_ADVISE -extern lt_dladvise opal_mca_dladvise; -#endif -#endif /* OPAL_WANT_LIBLTDL */ +#endif /* OPAL_HAVE_DL_SUPPORT */ -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT /* * Private functions */ static void find_dyn_components(const char *path, const char *type, const char **names, bool include_mode, opal_list_t *found_components); -static int save_filename(const char *filename, lt_ptr data); +static int save_filename(const char *filename, void *data); static int open_component(component_file_item_t *target_file, opal_list_t *found_components); static int check_opal_info(component_file_item_t *target_file, @@ -131,7 +121,7 @@ static const char component_template[] = "mca_%s_"; static opal_list_t found_files; static char **found_filenames = NULL; static char *last_path_to_use = NULL; -#endif /* OPAL_WANT_LIBLTDL */ +#endif /* OPAL_HAVE_DL_SUPPORT */ static int component_find_check (const char *framework_name, char **requested_component_names, opal_list_t *components); @@ -196,7 +186,7 @@ int mca_base_component_find(const char *directory, const char *type, } } -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT /* Find any available dynamic components in the specified directory */ if (open_dso_components && !mca_base_component_disable_dlopen) { find_dyn_components(directory, type, @@ -228,7 +218,7 @@ int mca_base_component_find(const char *directory, const char *type, int mca_base_component_find_finalize(void) { -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT if (NULL != found_filenames) { opal_argv_free(found_filenames); found_filenames = NULL; @@ -306,18 +296,15 @@ int mca_base_components_filter (const char *framework_name, opal_list_t *compone return ret; } -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT /* * Open up all directories in a given path and search for components of * the specified type (and possibly of a given name). * - * Note that we use our own path iteration functionality (vs. ltdl's - * lt_dladdsearchdir() functionality) because we need to look at - * companion .ompi_info files in the same directory as the library to - * generate dependencies, etc. If we use the plain lt_dlopen() - * functionality, we would not get the directory name of the file - * finally opened in recursive dependency traversals. + * Note that we use our own path iteration functionality because we + * need to look at companion .ompi_info files in the same directory as + * the library to generate dependencies, etc. */ static void find_dyn_components(const char *path, const char *type_name, const char **names, bool include_mode, @@ -377,18 +364,18 @@ static void find_dyn_components(const char *path, const char *type_name, if ((0 == strcmp(dir, "USER_DEFAULT") || 0 == strcmp(dir, "USR_DEFAULT")) && NULL != mca_base_user_default_path) { - if (0 != lt_dlforeachfile(mca_base_user_default_path, - save_filename, NULL)) { + if (0 != opal_dl_foreachfile(mca_base_user_default_path, + save_filename, NULL)) { break; } } else if (0 == strcmp(dir, "SYS_DEFAULT") || 0 == strcmp(dir, "SYSTEM_DEFAULT")) { - if (0 != lt_dlforeachfile(mca_base_system_default_path, - save_filename, NULL)) { + if (0 != opal_dl_foreachfile(mca_base_system_default_path, + save_filename, NULL)) { break; } } else { - if (0 != lt_dlforeachfile(dir, save_filename, NULL)) { + if (0 != opal_dl_foreachfile(dir, save_filename, NULL)) { break; } } @@ -475,7 +462,7 @@ static void find_dyn_components(const char *path, const char *type_name, * Blindly save all filenames into an argv-style list. This function * is the callback from lt_dlforeachfile(). */ -static int save_filename(const char *filename, lt_ptr data) +static int save_filename(const char *filename, void *data) { opal_argv_append_nosize(&found_filenames, filename); return 0; @@ -508,9 +495,9 @@ static int file_exists(const char *filename, const char *ext) static int open_component(component_file_item_t *target_file, opal_list_t *found_components) { - lt_dlhandle component_handle; + opal_dl_handle_t *component_handle; mca_base_component_t *component_struct; - char *struct_name, *err; + char *struct_name; opal_list_t dependencies; opal_list_item_t *cur; mca_base_component_list_item_t *mitem; @@ -562,18 +549,14 @@ static int open_component(component_file_item_t *target_file, /* Now try to load the component */ -#if OPAL_HAVE_LTDL_ADVISE - component_handle = lt_dlopenadvise(target_file->filename, opal_mca_dladvise); -#else - component_handle = lt_dlopenext(target_file->filename); -#endif - if (NULL == component_handle) { - /* Apparently lt_dlerror() sometimes returns NULL! */ - const char *str = lt_dlerror(); - if (NULL != str) { - err = strdup(str); + char *err_msg; + if (OPAL_SUCCESS != + opal_dl_open(target_file->filename, true, false, &component_handle, + &err_msg)) { + if (NULL != err_msg) { + err_msg = strdup(err_msg); } else { - err = strdup("lt_dlerror() returned NULL!"); + err_msg = strdup("opal_dl_open() error message was NULL!"); } /* Because libltdl erroneously says "file not found" for any type of error -- which is especially misleading when the file @@ -581,17 +564,17 @@ static int open_component(component_file_item_t *target_file, (e.g., missing symbol) -- do some simple huersitics and if the file [probably] does exist, print a slightly better error message. */ - if (0 == strcmp("file not found", err) && + if (0 == strcmp("file not found", err_msg) && (file_exists(target_file->filename, "lo") || file_exists(target_file->filename, "so") || file_exists(target_file->filename, "dylib") || file_exists(target_file->filename, "dll"))) { - free(err); - err = strdup("perhaps a missing symbol, or compiled for a different version of Open MPI?"); + free(err_msg); + err_msg = strdup("perhaps a missing symbol, or compiled for a different version of Open MPI?"); } opal_output_verbose(vl, 0, "mca: base: component_find: unable to open %s: %s (ignored)", - target_file->filename, err); - free(err); + target_file->filename, err_msg); + free(err_msg); target_file->status = FAILED_TO_LOAD; free_dependency_list(&dependencies); return OPAL_ERR_BAD_PARAM; @@ -603,7 +586,7 @@ static int open_component(component_file_item_t *target_file, len = strlen(target_file->type) + strlen(target_file->name) + 32; struct_name = (char*)malloc(len); if (NULL == struct_name) { - lt_dlclose(component_handle); + opal_dl_close(component_handle); target_file->status = FAILED_TO_LOAD; free_dependency_list(&dependencies); return OPAL_ERR_OUT_OF_RESOURCE; @@ -614,25 +597,24 @@ static int open_component(component_file_item_t *target_file, mitem = OBJ_NEW(mca_base_component_list_item_t); if (NULL == mitem) { free(struct_name); - lt_dlclose(component_handle); + opal_dl_close(component_handle); target_file->status = FAILED_TO_LOAD; free_dependency_list(&dependencies); return OPAL_ERR_OUT_OF_RESOURCE; } - component_struct = (mca_base_component_t*)lt_dlsym(component_handle, struct_name); - if (NULL == component_struct) { - /* Apparently lt_dlerror() sometimes returns NULL! */ - const char *str = lt_dlerror(); - if (NULL == str) { - str = "lt_dlerror() returned NULL!"; + if (OPAL_SUCCESS != opal_dl_lookup(component_handle, struct_name, + (void**) &component_struct, &err_msg) || + NULL == component_struct) { + if (NULL == err_msg) { + err_msg = "opal_dl_loookup() error message was NULL!"; } opal_output_verbose(vl, 0, "mca: base: component_find: \"%s\" does not appear to be a valid " - "%s MCA dynamic component (ignored): %s", - target_file->basename, target_file->type, str); + "%s MCA dynamic component (ignored): %s", + target_file->basename, target_file->type, err_msg); free(mitem); free(struct_name); - lt_dlclose(component_handle); + opal_dl_close(component_handle); target_file->status = FAILED_TO_LOAD; free_dependency_list(&dependencies); return OPAL_ERR_BAD_PARAM; @@ -652,7 +634,7 @@ static int open_component(component_file_item_t *target_file, MCA_BASE_VERSION_RELEASE); free(mitem); free(struct_name); - lt_dlclose(component_handle); + opal_dl_close(component_handle); target_file->status = FAILED_TO_LOAD; free_dependency_list(&dependencies); return OPAL_ERR_BAD_PARAM; @@ -668,7 +650,7 @@ static int open_component(component_file_item_t *target_file, component_struct->mca_component_name); free(mitem); free(struct_name); - lt_dlclose(component_handle); + opal_dl_close(component_handle); target_file->status = FAILED_TO_LOAD; free_dependency_list(&dependencies); return OPAL_ERR_BAD_PARAM; @@ -945,7 +927,7 @@ static void free_dependency_list(opal_list_t *dependencies) OBJ_DESTRUCT(dependencies); } -#endif /* OPAL_WANT_LIBLTDL */ +#endif /* OPAL_HAVE_DL_SUPPORT */ static bool use_component(const bool include_mode, const char **requested_component_names, diff --git a/opal/mca/base/mca_base_component_repository.c b/opal/mca/base/mca_base_component_repository.c index ea1108d400d..35ba4e6a762 100644 --- a/opal/mca/base/mca_base_component_repository.c +++ b/opal/mca/base/mca_base_component_repository.c @@ -9,7 +9,7 @@ * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. - * Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2008-2015 Cisco Systems, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -26,21 +26,14 @@ #include #include -#if OPAL_WANT_LIBLTDL - #if OPAL_LIBLTDL_INTERNAL - #include "opal/libltdl/ltdl.h" - #else - #include "ltdl.h" - #endif -#endif - #include "opal/class/opal_list.h" #include "opal/mca/mca.h" #include "opal/mca/base/base.h" #include "opal/mca/base/mca_base_component_repository.h" +#include "opal/mca/dl/base/base.h" #include "opal/constants.h" -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT /* * Private types @@ -49,7 +42,7 @@ struct repository_item_t { opal_list_item_t super; char ri_type[MCA_BASE_MAX_TYPE_NAME_LEN + 1]; - lt_dlhandle ri_dlhandle; + opal_dl_handle_t *ri_dlhandle; const mca_base_component_t *ri_component_struct; opal_list_t ri_dependencies; }; @@ -70,7 +63,7 @@ static void di_destructor(opal_object_t *obj); static OBJ_CLASS_INSTANCE(dependency_item_t, opal_list_item_t, di_constructor, di_destructor); -#endif /* OPAL_WANT_LIBLTDL */ +#endif /* OPAL_HAVE_DL_SUPPORT */ /* @@ -79,7 +72,7 @@ static OBJ_CLASS_INSTANCE(dependency_item_t, opal_list_item_t, static bool initialized = false; -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT static opal_list_t repository; @@ -90,11 +83,7 @@ static opal_list_t repository; static repository_item_t *find_component(const char *type, const char *name); static int link_items(repository_item_t *src, repository_item_t *depend); -#if OPAL_HAVE_LTDL_ADVISE -lt_dladvise opal_mca_dladvise; -#endif - -#endif /* OPAL_WANT_LIBLTDL */ +#endif /* OPAL_HAVE_DL_SUPPORT */ /* @@ -105,29 +94,30 @@ int mca_base_component_repository_init(void) /* Setup internal structures */ if (!initialized) { -#if OPAL_WANT_LIBLTDL - /* Initialize libltdl */ - - if (lt_dlinit() != 0) { - return OPAL_ERR_OUT_OF_RESOURCE; - } - -#if OPAL_HAVE_LTDL_ADVISE - if (lt_dladvise_init(&opal_mca_dladvise)) { - return OPAL_ERR_OUT_OF_RESOURCE; - } - - if (lt_dladvise_ext(&opal_mca_dladvise)) { - return OPAL_ERROR; +#if OPAL_HAVE_DL_SUPPORT + + /* Initialize the dl framework */ + int ret = mca_base_framework_open(&opal_dl_base_framework, 0); + if (OPAL_SUCCESS != ret) { + opal_output(0, "%s %d:%s failed -- process will likely abort (open the dl framework returned %d instead of OPAL_SUCCESS)\n", + __FILE__, __LINE__, __func__, ret); + return ret; } - - if (lt_dladvise_global(&opal_mca_dladvise)) { - return OPAL_ERROR; - } -#endif + opal_dl_base_select(); + + /* Bump the refcount to indicate that this framework is "special" + -- it can't be finalized until all other frameworks have been + finalized. E.g., in opal/runtime/opal_info_support.c, there's + a loop calling mca_base_framework_close() on all OPAL + frameworks. But that function simply decrements each + framework's refcount, and if it's zero, closes it. This + additional increment ensures that the "dl" framework is not + closed as part of that loop. */ + ++opal_dl_base_framework.framework_refcnt; OBJ_CONSTRUCT(&repository, opal_list_t); #endif + initialized = true; } @@ -143,10 +133,10 @@ int mca_base_component_repository_init(void) * saved. */ int mca_base_component_repository_retain(char *type, - lt_dlhandle component_handle, + opal_dl_handle_t *component_handle, const mca_base_component_t *component_struct) { -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT repository_item_t *ri; /* Allocate a new repository item */ @@ -182,7 +172,7 @@ int mca_base_component_repository_retain(char *type, int mca_base_component_repository_retain_component(const char *type, const char *name) { -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT repository_item_t *ri = find_component(type, name); if (NULL != ri) { OBJ_RETAIN(ri); @@ -203,7 +193,7 @@ int mca_base_component_repository_link(const char *src_type, const char *depend_type, const char *depend_name) { -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT repository_item_t *src, *depend; /* Look up the two components */ @@ -232,7 +222,7 @@ int mca_base_component_repository_link(const char *src_type, */ void mca_base_component_repository_release(const mca_base_component_t *component) { -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT if (initialized) { repository_item_t *ri = find_component(component->mca_type_name, component->mca_component_name); @@ -249,12 +239,12 @@ void mca_base_component_repository_release(const mca_base_component_t *component */ void mca_base_component_repository_finalize(void) { -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT repository_item_t *ri, *next; #endif if (initialized) { -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT /* Have to be slightly careful about this because of dependencies, particularly on OS's where it matters (i.e., closing a @@ -275,22 +265,17 @@ void mca_base_component_repository_finalize(void) } } while (opal_list_get_size(&repository) > 0); -#if OPAL_HAVE_LTDL_ADVISE - if (lt_dladvise_destroy(&opal_mca_dladvise)) { - return; - } -#endif - - /* Close down libltdl */ - - lt_dlexit(); + /* Close the dl framework (see comment about refcnt in + mca_base_component_repository_init()) */ + --opal_dl_base_framework.framework_refcnt; + (void) mca_base_framework_close(&opal_dl_base_framework); #endif initialized = false; } } -#if OPAL_WANT_LIBLTDL +#if OPAL_HAVE_DL_SUPPORT static repository_item_t *find_component(const char *type, const char *name) { @@ -379,7 +364,7 @@ static void ri_destructor(opal_object_t *obj) } /* Close the component (and potentially unload it from memory */ - lt_dlclose(ri->ri_dlhandle); + opal_dl_close(ri->ri_dlhandle); /* It should be obvious, but I'll state it anyway because it bit me during debugging: after the dlclose(), the mca_base_component_t @@ -419,4 +404,4 @@ static void di_destructor(opal_object_t *obj) OBJ_RELEASE(di->di_repository_entry); } -#endif /* OPAL_WANT_LIBLTDL */ +#endif /* OPAL_HAVE_DL_SUPPORT */ diff --git a/opal/mca/base/mca_base_component_repository.h b/opal/mca/base/mca_base_component_repository.h index 9d33bca0b75..fba02334207 100644 --- a/opal/mca/base/mca_base_component_repository.h +++ b/opal/mca/base/mca_base_component_repository.h @@ -9,6 +9,7 @@ * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -21,6 +22,9 @@ #include "opal_config.h" +#include "opal/mca/dl/dl.h" +#include "opal/mca/dl/base/base.h" + BEGIN_C_DECLS OPAL_DECLSPEC int mca_base_component_repository_init(void); @@ -33,37 +37,9 @@ BEGIN_C_DECLS * the functions exported from one header file rather than to separate * retain_component() and retain() into two separate header files * (i.e., have a separate header file just for retain()). - * - * Note that internal to opal/mca/base, will *always* be - * included before this file, and is not included anywhere - * else in the OMPI tree. So checking for the LTDL_H preprocessor - * macro is a good indicator as to whether this file is being included - * from an opal/mca/base source file or not. If we are, then we need - * already have a real definition of lt_dlhandle. If we are being - * included from elsewhere, then will not previously have - * been included, LTDL_H will not be defined, and we need a fake - * definition of lt_dlhandle (or we'll get compile errors). So just - * typedef it to (void*). - * - * One more case that this handles is the --disable-dlopen case. In - * that case, even in opal/mca/base, we *won't* be including . - * Hence, LTDL_H won't be defined, so we'll end up typedefing - * lt_dlhandle to (void *). "But why does that matter?" you ask, "If - * we configure with --disable-dlopen, then lt_dlhandle shouldn't be - * used anywhere." Incorrect, Grasshopper. A small number of places - * (like the retain() function) are still prototyped, but have 99% of - * their innards #if'ed out -- i.e., they just return - * OPAL_ERR_NOT_SUPPORTED. Why was it coded up this way? I'm not - * entirely sure -- there may be a reason (and that reason may just be - * conservative coding), but I'm not really too inspired to look into - * it any further at this point. :-) */ -#if !defined(LTDL_H) - typedef void *lt_dlhandle; -#endif - OPAL_DECLSPEC int mca_base_component_repository_retain(char *type, - lt_dlhandle component_handle, + opal_dl_handle_t *component_handle, const mca_base_component_t *component_struct); OPAL_DECLSPEC int mca_base_component_repository_retain_component(const char *type, From c683500a2921f05b7172312801545384aadc844f Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Thu, 19 Feb 2015 13:53:19 -0800 Subject: [PATCH 5/9] debuggers: convert to opal_dl interface --- ompi/debuggers/Makefile.am | 12 +- .../core.lt-dlopen_test-1424445474-6373 | Bin 0 -> 622592 bytes ompi/debuggers/dlopen_test.c | 112 +++++++++--------- 3 files changed, 63 insertions(+), 61 deletions(-) create mode 100644 ompi/debuggers/core.lt-dlopen_test-1424445474-6373 diff --git a/ompi/debuggers/Makefile.am b/ompi/debuggers/Makefile.am index c7e57655842..d9b08e298bb 100644 --- a/ompi/debuggers/Makefile.am +++ b/ompi/debuggers/Makefile.am @@ -9,7 +9,7 @@ # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. -# Copyright (c) 2007-2013 Cisco Systems, Inc. All rights reserved. +# Copyright (c) 2007-2015 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow @@ -20,10 +20,7 @@ noinst_LTLIBRARIES = libdebuggers.la libompi_debugger_canary.la ompilib_LTLIBRARIES = libompi_dbg_msgq.la -check_PROGRAMS = predefined_gap_test predefined_pad_test -if OPAL_HAVE_DLOPEN -check_PROGRAMS += dlopen_test -endif +check_PROGRAMS = predefined_gap_test predefined_pad_test dlopen_test TESTS = $(check_PROGRAMS) @@ -44,11 +41,10 @@ headers = \ msgq_interface.h ompi_msgq_dll_defs.h # Simple checks to ensure that the DSOs are functional -# This test is only built if we have libltdl support. dlopen_test_SOURCES = dlopen_test.c -dlopen_test_CPPFLAGS = -I$(top_srcdir)/opal/libltdl -dlopen_test_LDADD = $(top_builddir)/opal/libltdl/libltdlc.la +dlopen_test_LDADD = $(top_builddir)/ompi/libmpi.la +dlopen_test_DEPENDENCIES = $(ompi_predefined_LDADD) predefined_gap_test_SOURCES = predefined_gap_test.c predefined_gap_test_LDFLAGS = $(WRAPPER_EXTRA_LDFLAGS) diff --git a/ompi/debuggers/core.lt-dlopen_test-1424445474-6373 b/ompi/debuggers/core.lt-dlopen_test-1424445474-6373 new file mode 100644 index 0000000000000000000000000000000000000000..dca2dc1a63f3553bb4b971dfcf1b75c9a8ef26de GIT binary patch literal 622592 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 gPn<(NevN<1eJMa_I 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

P3J?ydS>GoIX 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 N$w}<@3~rB0f3G zR@X-RRbYK>tk381)FvXnYR|^1s@has;p=Kc6zB@+sEre}$2%B!;W%8GO_slr|v?!7e|4kmBP zhSR|u9=#QcEpHcKAH6je%qr<<&L};Y3*Q<^WNmWj`?FXm2imf?IkWldy0tQ!t}B-= zogdEGq;oc~qRS>tCSuv}O}6^OrdJjZc89a!TjRP(WSzSck(_dM&VMo&yeZMElCA^u zn-bxi(i`c?Ms&qAEz&5_rOTtjy|yrxQ{w4fO|=XU+Uy7IHa7ohSkq)POTZ0NHkwSF z8psRlV#|n_%_z~Wdx*m01KGqeTh(Irs>Ld8MmuxixUD*|M0L(lbU$g7S1`1_d+K?n`F*>R}jjBaBwh($7Sb3Je7cQVt6o>fJ!PwSev&rwry_o z!93X;7WMO3&(L~9-qV{KuWM}ftrM+vn_+PPH}RBcXz9473D&Ak%L1`Qui?sf87r0) zu23su#-kTKbZx0?g7qb=7u=}?ERvQ*^v2=Asv6ca5GWK6OZqOjt5+3_?9Hx*RMOl^r@(3mEatTu0y|m> z&EVBsXQ*5Ytuj#`{irGXSd4l@3Y%x_j~3r zqsIkhHj{MC>ddE)*}aBBX*oGK_|$t_P9E~+Ehi(}wYT`%VU=nP{yP}f#(`Q)P)_zJ*dN_S;Nbzo;W z*&mL=9#(~SeMO}=|5@G>@U6Y3HE<59Zy8M<%3T&9g3F6GAY;Hs~GGb{~!Q!oymlbB$kZl^dv9&yGlp z#ydoQS4TU`yKa4JLZ4)y_^``?alg?Xc>?RX}(!+zrq7;r>*r&)wS(Tju2uDi5Z1CW5d^ zle=^EEn8u?rP&vOXxKr^BvP=4*L+>GZ#`@&!ggZ*Lo)37&9UF+wB6=1ciU3Q?ocG@ ztI*r%Ev+4}zuxXEhuIwV5q**y(O%!y*tj*YwZ$h|ukWy0a=YuZFH_Xxy*qJBx-Z@@ zw|7&KbhtbLd&I$Bxz}v$&Kq|ey*c2NS}j+7KOOI=z>EwDqk_6M8xG9zjP$dJf>z4?o`+O+#p8`_2Z<*is-pETH zdQG&=8h);BTU|%f@N4bX@b9eMFBV&Src3U85DXed%5Q}CzjY_ST~xB?Q2?xw#ZdsP zJ>w;J{yXR+XTA^AJx5CJ{1Rx>N3D@n)c`b)EZ!o`MtoaAjI3*w|Id`+rs0)kBdbt4O8@29uK|FrXMr-$Y z5k~BKv1xcwnf34s3#|vA{C)c`?!Wg@moD1#b2lU@pi{a0D$;f2=j zM~l7VH`MK@yYa}O-;GX|!K=xGoe<|e**yHKlEo*Ugz%fZB!4|Uqa|NHUg8~oSchb3 zMpnHSJPseR9-eR=v6dXRHXOA|Ha&7k+K(){Y-%bnJv@HokeC?wZ|5X7CN|Rf>3zkY zloW~y`429CQ74pkdiw891lrf!-z$^?|2|n=c9nc**ml~dzaX*yD08W!DRw`~0smtL zW??|~M;Q38!oXiWvhKrwnx5WsGJTp3GP?J&!t1w$b#mPGarCLH*YwcZrttr00fKD4G-Q1 zvSi_rEqlh(%bJG|Hw_E<&o5UB=_SL5FPnzbD#NE+Fmo(^cyihBaxdK3N-i3LRAS`4 z#V4LDxk!{0{o%y7KsI`hocNrKzzc74q`qPK;N^>p)Y%``{yXG-P_SekxF7I1;CX=O L0iFluoCp3NNf5VT literal 0 HcmV?d00001 diff --git a/ompi/debuggers/dlopen_test.c b/ompi/debuggers/dlopen_test.c index 1cbbd79f588..ba6117bfa13 100644 --- a/ompi/debuggers/dlopen_test.c +++ b/ompi/debuggers/dlopen_test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2010 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -13,9 +13,10 @@ #include #include -#include "opal/libltdl/ltdl.h" +#include "opal/runtime/opal.h" +#include "opal/mca/dl/base/base.h" -#if !OPAL_WANT_LIBLTDL +#if !OPAL_HAVE_DL_SUPPORT int main(int argc, char *argv[]) { /* If OPAL wasn't built with libltdl support, then skip this test */ @@ -23,7 +24,36 @@ int main(int argc, char *argv[]) return 77; } -#else /* OPAL_WANT_LIBLTDL */ +#else /* OPAL_HAVE_DL_SUPPORT */ + +static int try_open(const char *filename) +{ + char *err_msg; + opal_dl_handle_t *handle; + int ret; + + ret = opal_dl_open(filename, true, true, &handle, &err_msg); + if (OPAL_SUCCESS == ret) { + opal_dl_close(handle); + printf("File opened with private namespace, all passed\n"); + return 0; + } + + printf("Failed to open with private namespace: %s\n", err_msg); + printf("Retrying with global namespace\n"); + + ret = opal_dl_open(filename, true, false, &handle, &err_msg); + if (OPAL_SUCCESS == ret) { + opal_dl_close(handle); + printf("File opened with global namespace\n"); + return 0; + } + + fprintf(stderr, "File failed to open with global namespace: %s\n", + err_msg); + + return 2; +} static int do_test(void) { @@ -32,11 +62,6 @@ static int do_test(void) char full_filename[] = "./libompi_dbg_msgq.la"; char line[1024]; int happy; - lt_dlhandle dlhandle; - -#if OPAL_HAVE_LTDL_ADVISE - lt_dladvise dladvise; -#endif /* Double check that the .la file is there that we expect; if it's not, skip this test. */ @@ -74,60 +99,41 @@ static int do_test(void) exit(77); } - /* Startup LT */ - if (lt_dlinit() != 0) { - fprintf(stderr, "Failed to lt_dlinit\n"); - return 1; - } + char cwd[4096]; + getcwd(cwd, sizeof(cwd) - 1); + cwd[sizeof(cwd) - 1] = '\0'; + printf("Running in CWD: %s\n", cwd); - printf("Trying to lt_dlopen file with dladvise_local: %s\n", filename); + printf("Trying to open file with private namespace: %s\n", filename); -#if OPAL_HAVE_LTDL_ADVISE - if (lt_dladvise_init(&dladvise) || - lt_dladvise_ext(&dladvise) || - lt_dladvise_local(&dladvise)) { - fprintf(stderr, "lt_dladvise failed to initialize properly\n"); - return 1; - } - dlhandle = lt_dlopenadvise(filename, dladvise); - lt_dladvise_destroy(&dladvise); -#else - dlhandle = lt_dlopenext(filename); -#endif - if (NULL != dlhandle) { - lt_dlclose(dlhandle); - printf("File opened with dladvise_local, all passed\n"); + /* If that works, great */ + if (0 == try_open(filename)) { return 0; } - printf("Failed to open with dladvise_local: %s\n", lt_dlerror()); - printf("Retrying with dladvise_global\n"); - -#if OPAL_HAVE_LTDL_ADVISE - if (lt_dladvise_init(&dladvise) || - lt_dladvise_ext(&dladvise) || - lt_dladvise_global(&dladvise)) { - fprintf(stderr, "lt_dladvise failed to initialize properly\n"); + /* If we're using libltdl, it will find the .la file and may + discover that it needs to open the actual file in the .libs + directory. If we're not using libltdl, then we won't know + about the magic .la file / .libs directory. Hueristic: if we + get here, manually prefix the filename with .libs/ and try + again. */ + char *rel_filename; + asprintf(&rel_filename, ".libs/%s", filename); + if (NULL == rel_filename) { return 1; } - dlhandle = lt_dlopenadvise(filename, dladvise); - lt_dladvise_destroy(&dladvise); -#else - dlhandle = lt_dlopenext(filename); -#endif - if (NULL != dlhandle) { - lt_dlclose(dlhandle); - printf("File opened with dladvise_global\n"); - return 0; - } - fprintf(stderr, "File failed to open with dladvise_global: %s\n", - lt_dlerror()); + int rc = try_open(rel_filename); + free(rel_filename); - return 2; + return rc; } int main(int argc, char *argv[]) { - return do_test(); + opal_init(&argc, &argv); + int ret = do_test(); + opal_finalize(); + + return ret; } -#endif /* OPAL_WANT_LIBLTDL */ +#endif /* OPAL_HAVE_DL_SUPPORT */ From 1995f6bebac4d6d9530c0a045a8fbf64c14bf614 Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Thu, 19 Feb 2015 13:59:44 -0800 Subject: [PATCH 6/9] cuda: convert to opal_dl interface --- config/opal_check_cuda.m4 | 30 +++- configure.ac | 12 ++ opal/mca/common/cuda/common_cuda.c | 169 +++++++----------- opal/mca/common/cuda/help-mpi-common-cuda.txt | 13 +- 4 files changed, 103 insertions(+), 121 deletions(-) diff --git a/config/opal_check_cuda.m4 b/config/opal_check_cuda.m4 index f9af756ce2c..7040f5c515b 100644 --- a/config/opal_check_cuda.m4 +++ b/config/opal_check_cuda.m4 @@ -10,7 +10,7 @@ dnl Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, dnl University of Stuttgart. All rights reserved. dnl Copyright (c) 2004-2005 The Regents of the University of California. dnl All rights reserved. -dnl Copyright (c) 2006-2010 Cisco Systems, Inc. All rights reserved. +dnl Copyright (c) 2006-2015 Cisco Systems, Inc. All rights reserved. dnl Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. dnl Copyright (c) 2009 IBM Corporation. All rights reserved. dnl Copyright (c) 2009 Los Alamos National Security, LLC. All rights @@ -72,10 +72,12 @@ AS_IF([test "$with_cuda" = "no" || test "x$with_cuda" = "x"], opal_cuda_incdir="$with_cuda/include" AC_MSG_RESULT([found ($opal_cuda_incdir/cuda.h)])])])])]) -# We cannot have CUDA support without dlopen support. Check for that and -# error out if the user has also set --disable-dlopen. -AS_IF([test "$enable_dlopen" = "no" && test "$opal_check_cuda_happy" = "yes"], - [AC_MSG_ERROR([--with-cuda cannot be used with --disable-dlopen. Remove one of them and reconfigure.])]) +dnl We cannot have CUDA support without dlopen support. HOWEVER, at +dnl this point in configure, we can't know whether the DL framework +dnl has been configured or not yet (it likely hasn't, since CUDA is a +dnl common framework, and likely configured first). So we have to +dnl defer this check until later (see the OPAL_CHECK_CUDA_AFTER_OPAL_DL m4 +dnl macro, below). :-( # If we have CUDA support, check to see if we have CUDA 4.1 support AS_IF([test "$opal_check_cuda_happy"="yes"], @@ -142,3 +144,21 @@ AC_DEFINE_UNQUOTED([OPAL_CUDA_GDR_SUPPORT],$CUDA_VERSION_60_OR_GREATER, [Whether we have CUDA GDR support available]) ]) + +dnl +dnl CUDA support requires DL support (it dynamically opens the CUDA +dnl library at run time). But we do not check for OPAL DL support +dnl until lafter the initial OPAL_CHECK_CUDA is called. So put the +dnl CUDA+DL check in a separate macro that can be called after the DL MCA +dnl framework checks in the top-level configure.ac. +dnl +AC_DEFUN([OPAL_CHECK_CUDA_AFTER_OPAL_DL],[ + + # We cannot have CUDA support without OPAL DL support. Error out + # if the user wants CUDA but we do not have OPAL DL support. + AS_IF([test $OPAL_HAVE_DL_SUPPORT -eq 0 && \ + test "$opal_check_cuda_happy" = "yes"], + [AC_MSG_WARN([--with-cuda was specified, but dlopen support is disabled.]) + AC_MSG_WARN([You must reconfigure Open MPI with dlopen ("dl") support.]) + AC_MSG_ERROR([Cannot continue.])]) +]) diff --git a/configure.ac b/configure.ac index 6e0048c5a70..713b97f4aed 100644 --- a/configure.ac +++ b/configure.ac @@ -1157,6 +1157,18 @@ m4_ifdef([project_ompi], [OMPI_REQUIRE_ENDPOINT_TAG_FINI]) # checkpoint results AC_CACHE_SAVE +################################## +# CUDA: part two +################################## + +# This is somewhat gross to have a configure check for a common MCA +# component outside of the normal MCA checks, but this check must come +# after the opal DL MCA checks have done. Someday this could perhaps +# be done better by having some kind of "run this check at the end of +# all other MCA checks" hook...? + +OPAL_CHECK_CUDA_AFTER_OPAL_DL + ################################## # MPI Extended Interfaces ################################## diff --git a/opal/mca/common/cuda/common_cuda.c b/opal/mca/common/cuda/common_cuda.c index 57d438ec78c..ed02de33de3 100644 --- a/opal/mca/common/cuda/common_cuda.c +++ b/opal/mca/common/cuda/common_cuda.c @@ -10,6 +10,7 @@ * Copyright (c) 2004-2006 The Regents of the University of California. * All rights reserved. * Copyright (c) 2011-2015 NVIDIA Corporation. All rights reserved. + * Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -33,13 +34,13 @@ #include "opal/datatype/opal_convertor.h" #include "opal/datatype/opal_datatype_cuda.h" #include "opal/util/output.h" -#include "opal/util/lt_interface.h" #include "opal/util/show_help.h" #include "opal/util/proc.h" #include "opal/mca/mpool/base/base.h" #include "opal/runtime/opal_params.h" #include "opal/mca/timer/base/base.h" +#include "opal/mca/dl/base/base.h" #include "common_cuda.h" @@ -55,12 +56,15 @@ #define OPAL_CUDA_DLSYM(libhandle, funcName) \ do { \ - *(void **)(&cuFunc.funcName) = opal_lt_dlsym(libhandle, STRINGIFY(funcName)); \ - if (NULL == cuFunc.funcName) { \ + char *err_msg; \ + void *ptr; \ + if (OPAL_SUCCESS != \ + opal_dl_lookup(libhandle, STRINGIFY(funcName), &ptr, &err_msg)) { \ opal_show_help("help-mpi-common-cuda.txt", "dlsym failed", true, \ - STRINGIFY(funcName), opal_lt_dlerror()); \ + STRINGIFY(funcName), err_msg); \ return 1; \ } else { \ + *(void **)(&cuFunc.funcName) = ptr; \ opal_output_verbose(15, mca_common_cuda_output, \ "CUDA: successful dlsym of %s", \ STRINGIFY(funcName)); \ @@ -185,7 +189,7 @@ static int cuda_event_dtoh_most = 0; static int cuda_event_htod_most = 0; /* Handle to libcuda.so */ -opal_lt_dlhandle libcuda_handle = NULL; +opal_dl_handle_t *libcuda_handle = NULL; /* Unused variable that we register at init time and unregister at fini time. * This is used to detect if user has done a device reset prior to MPI_Finalize. @@ -233,9 +237,7 @@ static void cuda_dump_memhandle(int, void *, char *) __opal_attribute_unused__ ; */ int mca_common_cuda_stage_one_init(void) { - opal_lt_dladvise advise; int retval, i, j; - int advise_support = 1; char *cudalibs[] = {"libcuda.so.1", "libcuda.dylib", NULL}; char *searchpaths[] = {"", "/usr/lib64", NULL}; char **errmsgs = NULL; @@ -339,120 +341,76 @@ int mca_common_cuda_stage_one_init(void) return 1; } - if (0 != (retval = opal_lt_dlinit())) { - if (OPAL_ERR_NOT_SUPPORTED == retval) { - opal_show_help("help-mpi-common-cuda.txt", "dlopen disabled", true); - } else { - opal_show_help("help-mpi-common-cuda.txt", "unknown ltdl error", true, - "opal_lt_dlinit", retval, opal_lt_dlerror()); - } + if (!OPAL_HAVE_DL_SUPPORT) { + opal_show_help("help-mpi-common-cuda.txt", "dlopen disabled", true); return 1; } - /* Initialize the lt_dladvise structure. If this does not work, we can - * proceed without the support. Things should still work. */ - if (0 != (retval = opal_lt_dladvise_init(&advise))) { - if (OPAL_ERR_NOT_SUPPORTED == retval) { - advise_support = 0; - } else { - opal_show_help("help-mpi-common-cuda.txt", "unknown ltdl error", true, - "opal_lt_dladvise_init", retval, opal_lt_dlerror()); - return 1; - } - } - /* Now walk through all the potential names libcuda and find one * that works. If it does, all is good. If not, print out all * the messages about why things failed. This code was careful * to try and save away all error messages if the loading ultimately - * failed to help with debugging. + * failed to help with debugging. + * * NOTE: On the first loop we just utilize the default loading * paths from the system. For the second loop, set /usr/lib64 to * the search path and try again. This is done to handle the case - * where we have both 32 and 64 bit libcuda.so libraries installed. - * Even when running in 64-bit mode, the /usr/lib directory - * is searched first and we may find a 32-bit libcuda.so.1 library. - * Loading of this library will fail as libtool does not handle having - * the wrong ABI in the search path (unlike ld or ld.so). Note that - * we only set this search path after the original search. This is - * so that LD_LIBRARY_PATH and run path settings are respected. - * Setting this search path overrides them (rather then being appended). */ - if (advise_support) { - if (0 != (retval = opal_lt_dladvise_global(&advise))) { - opal_show_help("help-mpi-common-cuda.txt", "unknown ltdl error", true, - "opal_lt_dladvise_global", retval, opal_lt_dlerror()); - opal_lt_dladvise_destroy(&advise); - return 1; - } - j = 0; - while (searchpaths[j] != NULL) { - /* Set explicit search path if entry is not empty string */ - if (strcmp("", searchpaths[j])) { - opal_lt_dlsetsearchpath(searchpaths[j]); - } - i = 0; - while (cudalibs[i] != NULL) { - const char *str; - libcuda_handle = opal_lt_dlopenadvise(cudalibs[i], advise); - if (NULL == libcuda_handle) { - str = opal_lt_dlerror(); - if (NULL != str) { - opal_argv_append(&errsize, &errmsgs, str); - } else { - opal_argv_append(&errsize, &errmsgs, "lt_dlerror() returned NULL."); - } - opal_output_verbose(10, mca_common_cuda_output, - "CUDA: Library open error: %s", - errmsgs[errsize-1]); - } else { - opal_output_verbose(10, mca_common_cuda_output, - "CUDA: Library successfully opened %s", - cudalibs[i]); - stage_one_init_passed = true; - break; - } - i++; + * where we have both 32 and 64 bit libcuda.so libraries + * installed. Even when running in 64-bit mode, the /usr/lib + * directory is searched first and we may find a 32-bit + * libcuda.so.1 library. Loading of this library will fail as the + * OPAL DL framework does not handle having the wrong ABI in the + * search path (unlike ld or ld.so). Note that we only set this + * search path after the original search. This is so that + * LD_LIBRARY_PATH and run path settings are respected. Setting + * this search path overrides them (rather then being + * appended). */ + j = 0; + while (searchpaths[j] != NULL) { + while (cudalibs[i] != NULL) { + char *filename; + char *str; + + /* If there's a non-empty search path, prepend it + to the library filename */ + if (strlen(searchpaths[j]) > 0) { + asprintf(&filename, "%s/%s", searchpaths[j], cudalibs[i]); + } else { + filename = strdup(cudalibs[i]); } - if (true == stage_one_init_passed) break; /* Break out of outer loop */ - j++; - } - opal_lt_dladvise_destroy(&advise); - } else { - j = 0; - /* No lt_dladvise support. This should rarely happen. */ - while (searchpaths[j] != NULL) { - /* Set explicit search path if entry is not empty string */ - if (strcmp("", searchpaths[j])) { - opal_lt_dlsetsearchpath(searchpaths[j]); + if (NULL == filename) { + opal_show_help("help-mpi-common-cuda.txt", "No memory", + true, OPAL_PROC_MY_HOSTNAME); + return 1; } - i = 0; - while (cudalibs[i] != NULL) { - const char *str; - libcuda_handle = opal_lt_dlopen(cudalibs[i]); - if (NULL == libcuda_handle) { - str = opal_lt_dlerror(); - if (NULL != str) { - opal_argv_append(&errsize, &errmsgs, str); - } else { - opal_argv_append(&errsize, &errmsgs, "lt_dlerror() returned NULL."); - } - - opal_output_verbose(10, mca_common_cuda_output, - "CUDA: Library open error: %s", - errmsgs[errsize-1]); + retval = opal_dl_open(filename, false, false, + &libcuda_handle, &str); + if (OPAL_SUCCESS != retval || NULL == libcuda_handle) { + if (NULL != str) { + opal_argv_append(&errsize, &errmsgs, str); } else { - opal_output_verbose(10, mca_common_cuda_output, - "CUDA: Library successfully opened %s", - cudalibs[i]); - stage_one_init_passed = true; - break; + opal_argv_append(&errsize, &errmsgs, + "opal_dl_open() returned NULL."); } - i++; + opal_output_verbose(10, mca_common_cuda_output, + "CUDA: Library open error: %s", + errmsgs[errsize-1]); + } else { + opal_output_verbose(10, mca_common_cuda_output, + "CUDA: Library successfully opened %s", + cudalibs[i]); + stage_one_init_passed = true; + break; } - if (true == stage_one_init_passed) break; /* Break out of outer loop */ - j++; + i++; + + free(filename); + } + if (true == stage_one_init_passed) { + break; /* Break out of outer loop */ } + j++; } if (true != stage_one_init_passed) { @@ -916,8 +874,7 @@ void mca_common_cuda_fini(void) OBJ_DESTRUCT(&common_cuda_dtoh_lock); OBJ_DESTRUCT(&common_cuda_ipc_lock); if (NULL != libcuda_handle) { - opal_lt_dlclose(libcuda_handle); - opal_lt_dlexit(); + opal_dl_close(libcuda_handle); } opal_output_verbose(20, mca_common_cuda_output, diff --git a/opal/mca/common/cuda/help-mpi-common-cuda.txt b/opal/mca/common/cuda/help-mpi-common-cuda.txt index 57a791ce9dc..c73b79c7227 100644 --- a/opal/mca/common/cuda/help-mpi-common-cuda.txt +++ b/opal/mca/common/cuda/help-mpi-common-cuda.txt @@ -1,10 +1,11 @@ # -*- text -*- # # Copyright (c) 2011-2015 NVIDIA. All rights reserved. +# Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ -# +# # Additional copyrights may follow -# +# # $HEADER$ # [cuCtxGetCurrent failed not initialized] @@ -152,14 +153,6 @@ Open MPI was compiled without dynamic library support (e.g., with the If you need CUDA support, reconfigure Open MPI with dynamic library support enabled. # -[unknown ltdl error] -While attempting to load the supporting libcuda.so library, an error -occurred. This really should rarely happen. Please notify the Open -MPI developers. - Function: %s - Return Value: %d - Error string: %s -# [dlopen failed] The library attempted to open the following supporting CUDA libraries, but each of them failed. CUDA-aware support is disabled. From 0a2767a5d33cf652245fce03a21ec76b197ae15a Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Thu, 19 Feb 2015 13:52:51 -0800 Subject: [PATCH 7/9] opal lt_interface: remove in favor of opal_dl interface --- opal/util/Makefile.am | 2 - opal/util/lt_interface.c | 246 --------------------------------------- opal/util/lt_interface.h | 72 ------------ 3 files changed, 320 deletions(-) delete mode 100644 opal/util/lt_interface.c delete mode 100644 opal/util/lt_interface.h diff --git a/opal/util/Makefile.am b/opal/util/Makefile.am index c36fb5eb32f..cedf860bf7b 100644 --- a/opal/util/Makefile.am +++ b/opal/util/Makefile.am @@ -47,7 +47,6 @@ headers = \ fd.c \ if.h \ keyval_parse.h \ - lt_interface.h \ malloc.h \ net.h \ numtostr.h \ @@ -83,7 +82,6 @@ libopalutil_la_SOURCES = \ if.c \ keyval_parse.c \ malloc.c \ - lt_interface.c \ net.c \ numtostr.c \ opal_environ.c \ diff --git a/opal/util/lt_interface.c b/opal/util/lt_interface.c deleted file mode 100644 index 59aa322b6e5..00000000000 --- a/opal/util/lt_interface.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2013-2015 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. - * $COPYRIGHT$ - * - * Additional copyrights may follow - * - * $HEADER$ - */ - -#include "opal_config.h" -#include -#include -#include "opal/constants.h" -#include "opal/util/lt_interface.h" -#include "opal/util/output.h" - -#if OPAL_WANT_LIBLTDL - #if OPAL_LIBLTDL_INTERNAL - #include "opal/libltdl/ltdl.h" - #else - #include "ltdl.h" - #endif -#endif - -#if OPAL_WANT_LIBLTDL -struct opal_lt_dlhandle_st { lt_dlhandle dlhandle; }; -#else /* OPAL_WANT_LIBLTDL */ -struct opal_lt_dlhandle_st { void *dlhandle; }; -#endif /* OPAL_WANT_LIBLTDL */ - -#if OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE -struct opal_lt_dladvise_st { lt_dladvise dladvise; }; -#else /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ -struct opal_lt_dladvise_st { void *dladvise; }; -#endif /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ - -OPAL_DECLSPEC int opal_lt_dlinit(void) -{ -#if OPAL_WANT_LIBLTDL - return lt_dlinit(); -#else /* OPAL_WANT_LIBLTDL */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL */ -} - -OPAL_DECLSPEC int opal_lt_dlexit(void) { -#if OPAL_WANT_LIBLTDL - return lt_dlexit(); -#else /* OPAL_WANT_LIBLTDL */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL */ -} - -/* Module search path manipulation. */ -OPAL_DECLSPEC int opal_lt_dladdsearchdir(const char *search_dir) { -#if OPAL_WANT_LIBLTDL - return lt_dladdsearchdir(search_dir); -#else /* OPAL_WANT_LIBLTDL */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL */ -} - -OPAL_DECLSPEC int opal_lt_dlinsertsearchdir(const char *before, - const char *search_dir) { -#if OPAL_WANT_LIBLTDL - return lt_dlinsertsearchdir(before, search_dir); -#else /* OPAL_WANT_LIBLTDL */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL */ -} - -OPAL_DECLSPEC int opal_lt_dlsetsearchpath(const char *search_path) { -#if OPAL_WANT_LIBLTDL - return lt_dlsetsearchpath(search_path); -#else /* OPAL_WANT_LIBLTDL */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL */ -} - -OPAL_DECLSPEC const char *opal_lt_dlgetsearchpath(void) { -#if OPAL_WANT_LIBLTDL - return lt_dlgetsearchpath(); -#else /* OPAL_WANT_LIBLTDL */ - return NULL; -#endif /* OPAL_WANT_LIBLTDL */ -} -OPAL_DECLSPEC int opal_lt_dlforeachfile(const char *search_path, - int (*func) (const char *filename, void *data), - void *data) { -#if OPAL_WANT_LIBLTDL - return lt_dlforeachfile(search_path, func, data); -#else /* OPAL_WANT_LIBLTDL */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL */ -} - -/* User module loading advisors. */ -OPAL_DECLSPEC int opal_lt_dladvise_init(opal_lt_dladvise *advise) { -#if OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE - *advise = malloc(sizeof(struct opal_lt_dladvise_st)); - if (NULL == *advise) { - return OPAL_ERR_OUT_OF_RESOURCE; - } - return lt_dladvise_init(&(*advise)->dladvise); -#else /* OPAL_WANT_LIBLTDL */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL */ -} - -OPAL_DECLSPEC int opal_lt_dladvise_destroy(opal_lt_dladvise *advise) { -#if OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE - int retval = lt_dladvise_destroy(&(*advise)->dladvise); - free(*advise); - return retval; -#else /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ -} - -OPAL_DECLSPEC int opal_lt_dladvise_ext(opal_lt_dladvise *advise) { -#if OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE - assert(advise); - return lt_dladvise_ext(&(*advise)->dladvise); -#else /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ -} - -OPAL_DECLSPEC int opal_lt_dladvise_resident(opal_lt_dladvise *advise) { -#if OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE - assert(advise); - return lt_dladvise_resident(&(*advise)->dladvise); -#else /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ -} - -OPAL_DECLSPEC int opal_lt_dladvise_local(opal_lt_dladvise *advise) { -#if OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE - assert(advise); - return lt_dladvise_local(&(*advise)->dladvise); -#else /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ -} - -OPAL_DECLSPEC int opal_lt_dladvise_global(opal_lt_dladvise *advise) { -#if OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE - assert(advise); - return lt_dladvise_global(&(*advise)->dladvise); -#else /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ -} - -OPAL_DECLSPEC int opal_lt_dladvise_preload(opal_lt_dladvise *advise) { -#if OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE - assert(advise); - return lt_dladvise_preload(&(*advise)->dladvise); -#else /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ - return OPAL_ERR_NOT_SUPPORTED; -#endif /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ -} - -/* Portable libltdl versions of the system dlopen() API. */ -OPAL_DECLSPEC opal_lt_dlhandle opal_lt_dlopen(const char *filename) { -#if OPAL_WANT_LIBLTDL - opal_lt_dlhandle handle; - handle = malloc(sizeof(struct opal_lt_dlhandle_st)); - if (NULL == handle) { - return NULL; - } - handle->dlhandle = lt_dlopen(filename); - if (NULL == handle->dlhandle) { - free(handle); - return NULL; - } - return handle; -#else /* OPAL_WANT_LIBLTDL */ - return NULL; -#endif /* OPAL_WANT_LIBLTDL */ -} - -OPAL_DECLSPEC opal_lt_dlhandle opal_lt_dlopenext(const char *filename) { -#if OPAL_WANT_LIBLTDL - opal_lt_dlhandle handle; - handle = malloc(sizeof(struct opal_lt_dlhandle_st)); - if (NULL == handle) { - return NULL; - } - handle->dlhandle = lt_dlopenext(filename); - if (NULL == handle->dlhandle) { - free(handle); - return NULL; - } - return handle; -#else /* OPAL_WANT_LIBLTDL */ - return NULL; -#endif /* OPAL_WANT_LIBLTDL */ -} - -OPAL_DECLSPEC void *opal_lt_dlsym(opal_lt_dlhandle handle, const char *name) { -#if OPAL_WANT_LIBLTDL - return lt_dlsym(handle->dlhandle, name); -#else /* OPAL_WANT_LIBLTDL */ - return NULL; -#endif /* OPAL_WANT_LIBLTDL */ -} - -OPAL_DECLSPEC const char *opal_lt_dlerror(void) { -#if OPAL_WANT_LIBLTDL - return lt_dlerror(); -#else /* OPAL_WANT_LIBLTDL */ - return NULL; -#endif /* OPAL_WANT_LIBLTDL */ -} - -OPAL_DECLSPEC int opal_lt_dlclose(opal_lt_dlhandle handle) { -#if OPAL_WANT_LIBLTDL - int retval = lt_dlclose(handle->dlhandle); - free(handle); - return retval; -#else - return OPAL_ERR_NOT_SUPPORTED; -#endif -} - -OPAL_DECLSPEC opal_lt_dlhandle opal_lt_dlopenadvise(const char *filename, - opal_lt_dladvise advise) { -#if OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE - opal_lt_dlhandle handle; - handle = malloc(sizeof(struct opal_lt_dlhandle_st)); - if (NULL == handle) { - return NULL; - } - handle->dlhandle = lt_dlopenadvise(filename, advise->dladvise); - if (NULL == handle->dlhandle) { - free(handle); - return NULL; - } - return handle; -#else /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ - return NULL; -#endif /* OPAL_WANT_LIBLTDL && OPAL_HAVE_LTDL_ADVISE */ -} diff --git a/opal/util/lt_interface.h b/opal/util/lt_interface.h deleted file mode 100644 index 0fb8cd5825e..00000000000 --- a/opal/util/lt_interface.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. - * $COPYRIGHT$ - * - * Additional copyrights may follow - * - * $HEADER$ - */ - -/** -* Wrappers to LTDL functions so that other parts of library can -* access the LTDL functionality that is embedded/linked in to Open -* MPI (vs. a LTDL library that was linked in by the application). -* The OPAL-linked LTDL library is intentionally not DECLSPEC'ed so -* that it is not visible to upper-layer applications; its functions -* are provided to the rest of the OMPI code base via the following -* OPAL wrappers. -* For functions that return int, if there are any failures, these -* functions can return both OPAL error codes and LTDL error codes. -* If the return code is negative it is OPAL, and if positive it -* follows the LTDL convention where the number represents the number -* of errors seen. You can then call opal_lt_dlerror() to get more -* information when you see a positive error code. -*/ - -/** - * Create opal_lt_dlhandle and opal_lt_dladvise types so that - * consumers of this code can use these opal types rather than the - * LTDL versions. In this way, there is no need to include the - * underlying ltdl.h here (it is only needed in lt_interface.c) and we - * do not need to use the OPAL_WANT_LIBLTDL and OPAL_HAVE_LTDL_ADVISE - * macros anywhere else. These types are effectively just pointers to - * the underlying LTDL types. - */ -struct opal_lt_dlhandle_st; -typedef struct opal_lt_dlhandle_st* opal_lt_dlhandle; -struct opal_lt_dladvise_st; -typedef struct opal_lt_dladvise_st* opal_lt_dladvise; - -/** - * Wrappers for the ltdl library. - */ -OPAL_DECLSPEC int opal_lt_dlinit(void); -OPAL_DECLSPEC int opal_lt_dlexit(void); - -/* Module search path manipulation. */ -OPAL_DECLSPEC int opal_lt_dladdsearchdir(const char *search_dir); -OPAL_DECLSPEC int opal_lt_dlinsertsearchdir(const char *before, - const char *search_dir); -OPAL_DECLSPEC int opal_lt_dlsetsearchpath(const char *search_path); -OPAL_DECLSPEC const char *opal_lt_dlgetsearchpath(void); -OPAL_DECLSPEC int opal_lt_dlforeachfile(const char *search_path, - int (*func) (const char *filename, void *data), - void *data); -/* User module loading advisors. */ -OPAL_DECLSPEC int opal_lt_dladvise_init(opal_lt_dladvise *advise); -OPAL_DECLSPEC int opal_lt_dladvise_destroy(opal_lt_dladvise *advise); -OPAL_DECLSPEC int opal_lt_dladvise_ext(opal_lt_dladvise *advise); -OPAL_DECLSPEC int opal_lt_dladvise_resident(opal_lt_dladvise *advise); -OPAL_DECLSPEC int opal_lt_dladvise_local(opal_lt_dladvise *advise); -OPAL_DECLSPEC int opal_lt_dladvise_global(opal_lt_dladvise *advise); -OPAL_DECLSPEC int opal_lt_dladvise_preload(opal_lt_dladvise *advise); - -/* Portable libltdl versions of the system dlopen() API. */ -OPAL_DECLSPEC opal_lt_dlhandle opal_lt_dlopen(const char *filename); -OPAL_DECLSPEC opal_lt_dlhandle opal_lt_dlopenext(const char *filename); -OPAL_DECLSPEC void *opal_lt_dlsym(opal_lt_dlhandle handle, const char *name); -OPAL_DECLSPEC const char *opal_lt_dlerror(void); -OPAL_DECLSPEC int opal_lt_dlclose(opal_lt_dlhandle handle); -OPAL_DECLSPEC opal_lt_dlhandle opal_lt_dlopenadvise(const char *filename, - opal_lt_dladvise advise); From a026456bef166b8896dad7b8b074d5467ef14e9d Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Sat, 21 Feb 2015 04:39:40 -0800 Subject: [PATCH 8/9] (orte|ompi|oshmem)*info tools: convert to opal_dl interface Noe that this commit removes option:lt_dladvise from the various "info" tools output. This technically breaks our CLI "ABI" because we're not deprecating it / replacing it with an alias to some other "into" tool output. Although the dl/libltdl component contains an "have_lt_dladvise" MCA var that contains the same information, the "option:lt_dladvise" output from the various "info" tools is *not* an MCA var, and therefore we can't alias it. So it just has to die. --- ompi/tools/ompi_info/param.c | 9 +++------ orte/tools/orte-info/param.c | 9 +++------ oshmem/tools/oshmem_info/param.c | 9 +++------ 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/ompi/tools/ompi_info/param.c b/ompi/tools/ompi_info/param.c index 885e1051370..dca5dfc76e7 100644 --- a/ompi/tools/ompi_info/param.c +++ b/ompi/tools/ompi_info/param.c @@ -118,8 +118,7 @@ void ompi_info_do_config(bool want_all) char *fortran_usempif08_profiling; char *cxxexceptions; char *threads; - char *want_libltdl; - char *have_ltdl_advise; + char *have_dl; #if OMPI_RTE_ORTE char *mpirun_prefix_by_default; #endif @@ -259,8 +258,7 @@ void ompi_info_do_config(bool want_all) fortran_mpifh_profiling = (OMPI_ENABLE_MPI_PROFILING && OMPI_BUILD_FORTRAN_MPIFH_BINDINGS) ? "yes" : "no"; fortran_usempi_profiling = (OMPI_ENABLE_MPI_PROFILING && OMPI_BUILD_FORTRAN_USEMPI_BINDINGS) ? "yes" : "no"; fortran_usempif08_profiling = (OMPI_ENABLE_MPI_PROFILING && OMPI_BUILD_FORTRAN_USEMPIF08_BINDINGS) ? "yes" : "no"; - want_libltdl = OPAL_WANT_LIBLTDL ? "yes" : "no"; - have_ltdl_advise = OPAL_HAVE_LTDL_ADVISE ? "yes" : "no"; + have_dl = OPAL_HAVE_DL_SUPPORT ? "yes" : "no"; #if OMPI_RTE_ORTE mpirun_prefix_by_default = ORTE_WANT_ORTERUN_PREFIX_BY_DEFAULT ? "yes" : "no"; #endif @@ -620,8 +618,7 @@ void ompi_info_do_config(bool want_all) opal_info_out("MPI parameter check", "option:mpi-param-check", paramcheck); opal_info_out("Memory profiling support", "option:mem-profile", memprofile); opal_info_out("Memory debugging support", "option:mem-debug", memdebug); - opal_info_out("libltdl support", "option:dlopen", want_libltdl); - opal_info_out("lt_dladvise support", "option:lt_dladvise", have_ltdl_advise); + opal_info_out("dl support", "option:dlopen", have_dl); opal_info_out("Heterogeneous support", "options:heterogeneous", heterogeneous); #if OMPI_RTE_ORTE opal_info_out("mpirun default --prefix", "mpirun:prefix_by_default", diff --git a/orte/tools/orte-info/param.c b/orte/tools/orte-info/param.c index a2f59aec4b7..9330799d766 100644 --- a/orte/tools/orte-info/param.c +++ b/orte/tools/orte-info/param.c @@ -339,8 +339,7 @@ void orte_info_do_config(bool want_all) char *memdebug; char *debug; char *threads; - char *want_libltdl; - char *have_ltdl_advise; + char *have_dl; char *orterun_prefix_by_default; char *wtime_support; char *symbol_visibility; @@ -351,8 +350,7 @@ void orte_info_do_config(bool want_all) memprofile = OPAL_ENABLE_MEM_PROFILE ? "yes" : "no"; memdebug = OPAL_ENABLE_MEM_DEBUG ? "yes" : "no"; debug = OPAL_ENABLE_DEBUG ? "yes" : "no"; - want_libltdl = OPAL_WANT_LIBLTDL ? "yes" : "no"; - have_ltdl_advise = OPAL_HAVE_LTDL_ADVISE ? "yes" : "no"; + have_dl = OPAL_HAVE_DL_SUPPORT ? "yes" : "no"; orterun_prefix_by_default = ORTE_WANT_ORTERUN_PREFIX_BY_DEFAULT ? "yes" : "no"; wtime_support = OPAL_TIMER_USEC_NATIVE ? "native" : "gettimeofday"; symbol_visibility = OPAL_C_HAVE_VISIBILITY ? "yes" : "no"; @@ -423,8 +421,7 @@ void orte_info_do_config(bool want_all) orte_info_out("Internal debug support", "option:debug", debug); orte_info_out("Memory profiling support", "option:mem-profile", memprofile); orte_info_out("Memory debugging support", "option:mem-debug", memdebug); - orte_info_out("libltdl support", "option:dlopen", want_libltdl); - orte_info_out("lt_dladvise support", "option:lt_dladvise", have_ltdl_advise); + orte_info_out("dl support", "option:dlopen", have_dl); orte_info_out("Heterogeneous support", "options:heterogeneous", heterogeneous); orte_info_out("orterun default --prefix", "orterun:prefix_by_default", orterun_prefix_by_default); diff --git a/oshmem/tools/oshmem_info/param.c b/oshmem/tools/oshmem_info/param.c index 7780ccfb705..999fa061502 100644 --- a/oshmem/tools/oshmem_info/param.c +++ b/oshmem/tools/oshmem_info/param.c @@ -108,8 +108,7 @@ void oshmem_info_do_config(bool want_all) char *fortran_usempif08_profiling; char *cxxexceptions; char *threads; - char *want_libltdl; - char *have_ltdl_advise; + char *have_dl; #if OMPI_RTE_ORTE char *mpirun_prefix_by_default; #endif @@ -234,8 +233,7 @@ void oshmem_info_do_config(bool want_all) fortran_mpifh_profiling = (OMPI_ENABLE_MPI_PROFILING && OMPI_BUILD_FORTRAN_MPIFH_BINDINGS) ? "yes" : "no"; fortran_usempi_profiling = (OMPI_ENABLE_MPI_PROFILING && OMPI_BUILD_FORTRAN_USEMPI_BINDINGS) ? "yes" : "no"; fortran_usempif08_profiling = (OMPI_ENABLE_MPI_PROFILING && OMPI_BUILD_FORTRAN_USEMPIF08_BINDINGS) ? "yes" : "no"; - want_libltdl = OPAL_WANT_LIBLTDL ? "yes" : "no"; - have_ltdl_advise = OPAL_HAVE_LTDL_ADVISE ? "yes" : "no"; + have_dl = OPAL_HAVE_DL_SUPPORT ? "yes" : "no"; #if OMPI_RTE_ORTE mpirun_prefix_by_default = ORTE_WANT_ORTERUN_PREFIX_BY_DEFAULT ? "yes" : "no"; #endif @@ -568,8 +566,7 @@ void oshmem_info_do_config(bool want_all) opal_info_out("MPI parameter check", "option:mpi-param-check", paramcheck); opal_info_out("Memory profiling support", "option:mem-profile", memprofile); opal_info_out("Memory debugging support", "option:mem-debug", memdebug); - opal_info_out("libltdl support", "option:dlopen", want_libltdl); - opal_info_out("lt_dladvise support", "option:lt_dladvise", have_ltdl_advise); + opal_info_out("dl support", "option:dlopen", have_dl); opal_info_out("Heterogeneous support", "options:heterogeneous", heterogeneous); #if OMPI_RTE_ORTE opal_info_out("mpirun default --prefix", "mpirun:prefix_by_default", From 914880a368566c9d56cd65cd153041cd3bc5759b Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Sat, 21 Feb 2015 04:42:55 -0800 Subject: [PATCH 9/9] libtldl: remove libltdl from the tree The libltdl interface has been completely replaced by the OPAL DL framework (i.e., the opal_dl interface). Fixes open-mpi/ompi#311 --- autogen.pl | 23 +-- config/Makefile.am | 3 +- config/libltdl-preopen-error.diff | 27 --- config/opal_configure_options.m4 | 2 +- config/opal_setup_libltdl.m4 | 195 ------------------ configure.ac | 4 - .../nightly/reports/check_devel_headers.pl | 6 +- opal/Makefile.am | 10 +- 8 files changed, 5 insertions(+), 265 deletions(-) delete mode 100644 config/libltdl-preopen-error.diff delete mode 100644 config/opal_setup_libltdl.m4 diff --git a/autogen.pl b/autogen.pl index d680d32c76d..9694250aafa 100755 --- a/autogen.pl +++ b/autogen.pl @@ -1,6 +1,6 @@ #!/usr/bin/env perl # -# Copyright (c) 2009-2014 Cisco Systems, Inc. All rights reserved. +# Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013 Mellanox Technologies, Inc. # All rights reserved. @@ -1265,7 +1265,6 @@ sub patch_autotools_output { verbose "==> Remove stale files\n"; find_and_delete(qw/config.guess config.sub depcomp compile install-sh ltconfig ltmain.sh missing mkinstalldirs libtool/); -system("rm -rf opal/libltdl"); # Remove the old m4 file and write the new one verbose "==> Writing m4 file with autogen.pl results\n"; @@ -1292,26 +1291,6 @@ sub patch_autotools_output { #--------------------------------------------------------------------------- -# For FreeBSD (carried over from autogen.sh); apparently some versions -# of automake don't so this (prior to 1.9.7...?). -system("chmod u+w opal/libltdl/configure"); - -#--------------------------------------------------------------------------- - -++$step; -verbose "\n$step. Patching autotools output on top-level tree :-(\n\n"; - -# Patch preopen error in libltdl -if (-f "opal/libltdl/loaders/preopen.c") { - verbose "=== Patching preopen error masking in libltdl\n"; - safe_system("$patch_prog -N -p0 < config/libltdl-preopen-error.diff"); - unlink("opal/libltdl/loaders/preopen.c.rej"); -} - -patch_autotools_output("."); - -#--------------------------------------------------------------------------- - verbose " ================================================ Open MPI autogen: completed successfully. w00t! diff --git a/config/Makefile.am b/config/Makefile.am index 3217f8fbfdf..5b534c77939 100644 --- a/config/Makefile.am +++ b/config/Makefile.am @@ -9,7 +9,7 @@ # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. -# Copyright (c) 2006-2010 Cisco Systems, Inc. All rights reserved. +# Copyright (c) 2006-2015 Cisco Systems, Inc. All rights reserved. # Copyright (c) 2010 Oracle and/or its affiliates. All rights # reserved. # Copyright (c) 2014 Intel, Inc. All rights reserved. @@ -23,7 +23,6 @@ EXTRA_DIST = \ distscript.csh \ opal_get_version.m4sh \ - libltdl-preopen-error.diff \ ltmain_pgi_tp.diff \ opal_mca_priority_sort.pl diff --git a/config/libltdl-preopen-error.diff b/config/libltdl-preopen-error.diff deleted file mode 100644 index 0112c746921..00000000000 --- a/config/libltdl-preopen-error.diff +++ /dev/null @@ -1,27 +0,0 @@ ---- opal/libltdl/loaders/preopen.c.~1~ 2010-03-03 14:13:28.000000000 -0500 -+++ opal/libltdl/loaders/preopen.c 2010-03-05 17:57:11.000000000 -0500 -@@ -185,7 +185,24 @@ - } - } - -+#if 0 -+ /* Open MPI: This line is commented out because Open MPI does not -+ use the preopen functionality in libltdl at all -- so we never -+ need to see errors from this module. Additionally, this module -+ is usually invoked last in the sequence when trying to -+ lt_dlopenadvise() a DSO -- so if there was a real error when -+ opening that DSO (e.g., a symbol not found), setting the -+ FILE_NOT_FOUND error here will mask the real error. -+ -+ This error has been reported upstream to the Libtool maintainers; -+ they acknowledge that it is a problem but no one has come up with -+ a good general solution yet. This Open MPI-specific solution is -+ workable for us, but not workable as a general solution. Hence, -+ we patch in this "if 0" block in autogen.pl after Libtool -+ installs libltdl in the opal/ tree. -+ */ - LT__SETERROR (FILE_NOT_FOUND); -+#endif - - done: - return module; diff --git a/config/opal_configure_options.m4 b/config/opal_configure_options.m4 index 92f286b7628..280f5d1ec42 100644 --- a/config/opal_configure_options.m4 +++ b/config/opal_configure_options.m4 @@ -10,7 +10,7 @@ dnl Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, dnl University of Stuttgart. All rights reserved. dnl Copyright (c) 2004-2005 The Regents of the University of California. dnl All rights reserved. -dnl Copyright (c) 2006-2014 Cisco Systems, Inc. All rights reserved. +dnl Copyright (c) 2006-2015 Cisco Systems, Inc. All rights reserved. dnl Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. dnl Copyright (c) 2009 IBM Corporation. All rights reserved. dnl Copyright (c) 2009 Los Alamos National Security, LLC. All rights diff --git a/config/opal_setup_libltdl.m4 b/config/opal_setup_libltdl.m4 deleted file mode 100644 index f89de1a19bf..00000000000 --- a/config/opal_setup_libltdl.m4 +++ /dev/null @@ -1,195 +0,0 @@ -dnl -dnl Copyright (c) 2004-2009 The Trustees of Indiana University and Indiana -dnl University Research and Technology -dnl Corporation. All rights reserved. -dnl Copyright (c) 2004-2005 The University of Tennessee and The University -dnl of Tennessee Research Foundation. All rights -dnl reserved. -dnl Copyright (c) 2004-2007 High Performance Computing Center Stuttgart, -dnl University of Stuttgart. All rights reserved. -dnl Copyright (c) 2004-2005 The Regents of the University of California. -dnl All rights reserved. -dnl Copyright (c) 2006-2014 Cisco Systems, Inc. All rights reserved. -dnl Copyright (c) 2006-2008 Sun Microsystems, Inc. All rights reserved. -dnl Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights -dnl reserved. -dnl Copyright (c) 2009 Oak Ridge National Labs. All rights reserved. -dnl $COPYRIGHT$ -dnl -dnl Additional copyrights may follow -dnl -dnl $HEADER$ -dnl - -AC_DEFUN([OPAL_SETUP_LIBLTDL],[ - OPAL_VAR_SCOPE_PUSH([HAPPY]) - - opal_show_subtitle "GNU libltdl setup" - - # AC_CONFIG_SUBDIRS appears to be broken for non-gcc compilers (i.e., - # passing precious variables down to the sub-configure). - # - # Finally, make ltdl follow the same shared/static convention that was - # user for the main OMPI libraries. So manually examine - # $enable_shared and $enable_static and pass down the corresponding - # flags. - - LIBLTDL_SUBDIR= - OPAL_HAVE_LTDL_ADVISE=0 - OPAL_LIBLTDL_INTERNAL=0 - - AS_IF([test "$OPAL_ENABLE_DLOPEN_SUPPORT" = "0"], - [AC_MSG_WARN([libltdl support disabled (by --disable-dlopen)]) - LIBLTDL= - LDTLINCL= - OPAL_WRAPPER_FLAGS_ADD(LIBS, "$LIBS")], - [ - # Default to building the internal copy. After this, - # paffinity_hwloc_location is guaranteed to be set to one of: - # "internal", a directory name (i.e., whatever the user - # supplied), or "no". - libltdl_location=$with_libltdl - AS_IF([test -z "$libltdl_location" -o "$libltdl_location" = "yes"], - [libltdl_location=internal]) - - AC_MSG_CHECKING([location of libltdl]) - case $libltdl_location in - no) - AC_MSG_WARN([--without-libltdl specified in conjunction with]) - AC_MSG_WARN([--enable-dlopen (or --disable-dlopen was not specified)]) - AC_MSG_WARN([Cannot have dlopen without libltdl]) - AC_MSG_ERROR([Cannot continue]) - ;; - internal) - AC_MSG_RESULT([internal copy]) - _OPAL_SETUP_LIBLTDL_INTERNAL - ;; - external) - AC_MSG_RESULT([external copy (unspecified)]) - # If we're using an extern libltdl, then reset the - # LTDLINCL that was set earlier (ie., there's no need to - # -I into our internal libltdl tree). - LIBLTDL= - LDTLINCL= - libltdl_location= - libltdl_need_external=1 - ;; - *) - AC_MSG_RESULT([external copy ($libltdl_location)]) - OPAL_CHECK_WITHDIR([libltdl], [$libltdl_location], - [include/ltdl.h]) - # If we're using an extern libltdl, then reset the - # LTDLINCL that was set earlier (ie., there's no need to - # -I into our internal libltdl tree). - LIBLTDL= - LDTLINCL= - libltdl_need_external=1 - ;; - esac - - AS_IF([test "$libltdl_need_external" = "1"], - [OPAL_CHECK_PACKAGE([libltdl], - [ltdl.h], - [ltdl], - [lt_dlopen], - [], - [$libltdl_location], - [], - [], - [AC_MSG_WARN([External libltdl installation not found]) - AC_MSG_WARN([or not usable.]) - AC_MSG_ERROR([Cannot continue.])]) - CPPFLAGS="$CPPFLAGS $libltdl_CPPFLAGS" - LDFLAGS="$LDFLAGS $libltdl_LDFLAGS" - LIBS="$LIBS $libltdl_LIBS" - - # Check for lt_dladvise_init; warn if we don't have - # it - AC_CHECK_FUNC([lt_dladvise_init], - [OPAL_HAVE_LTDL_ADVISE=1], - [AC_MSG_WARN([*********************************************]) - AC_MSG_WARN([Could not find lt_dladvise_init in the]) - AC_MSG_WARN([external libltdl installation.]) - AC_MSG_WARN([This could mean that your libltdl version]) - AC_MSG_WARN([is old. We recommend that you re-configure]) - AC_MSG_WARN([Open MPI with --with-libltdl=internal to]) - AC_MSG_WARN([use the internal libltdl copy in Open MPI.]) - AC_MSG_WARN([]) - AC_MSG_WARN([Sleeping 10 seconds to give you a]) - AC_MSG_WARN([chance to read this message.]) - AC_MSG_WARN([*********************************************]) - sleep 10 - ]) - ]) - ]) - - AC_SUBST(LTDLINCL) - AC_SUBST(LIBLTDL) - AC_SUBST(LIBLTDL_SUBDIR) - - AC_MSG_CHECKING([for lt_dladvise]) - AS_IF([test $OPAL_HAVE_LTDL_ADVISE -eq 1], - [AC_MSG_RESULT([yes])], - [AC_MSG_RESULT([no])]) - AC_DEFINE_UNQUOTED(OPAL_HAVE_LTDL_ADVISE, $OPAL_HAVE_LTDL_ADVISE, - [Whether libltdl appears to have the lt_dladvise interface]) - - AC_DEFINE_UNQUOTED(OPAL_WANT_LIBLTDL, $OPAL_ENABLE_DLOPEN_SUPPORT, - [Whether to include support for libltdl or not]) - AC_DEFINE_UNQUOTED(OPAL_LIBLTDL_INTERNAL, $OPAL_LIBLTDL_INTERNAL, - [Whether we are using the internal libltdl or not]) - - AM_CONDITIONAL(OPAL_HAVE_DLOPEN, - [test "$OPAL_ENABLE_DLOPEN_SUPPORT" = "1"]) - OPAL_VAR_SCOPE_POP([HAPPY]) -])dnl - - -# -# Setup to build the internal copy of libltdl -# -AC_DEFUN([_OPAL_SETUP_LIBLTDL_INTERNAL],[ - OPAL_VAR_SCOPE_PUSH([CFLAGS_save CPPFLAGS_save]) - - opal_subdir_args="$opal_subdir_args --enable-ltdl-convenience --disable-ltdl-install" - if test "$enable_shared" = "yes"; then - opal_subdir_args="$opal_subdir_args --enable-shared" - else - opal_subdir_args="$opal_subdir_args --disable-shared" - fi - if test "$enable_static" = "yes"; then - opal_subdir_args="$opal_subdir_args --enable-static" - else - opal_subdir_args="$opal_subdir_args --disable-static" - fi - - CFLAGS_save=$CFLAGS - CFLAGS="$OPAL_CFLAGS_BEFORE_PICKY $OPAL_VISIBILITY_CFLAGS" - - # VPATH support will be included by default in CONFIG_SUBDIR - OPAL_CONFIG_SUBDIR(opal/libltdl, [$opal_subdir_args], - [HAPPY=1], [HAPPY=0]) - if test $HAPPY -eq 1; then - LIBLTDL_SUBDIR=libltdl - OPAL_LIBLTDL_INTERNAL=1 - - CPPFLAGS_save=$CPPFLAGS - CPPFLAGS="-I$srcdir -I$srcdir/opal/libltdl" - AC_EGREP_HEADER([lt_dladvise_init], [opal/libltdl/ltdl.h], - [OPAL_HAVE_LTDL_ADVISE=1]) - CPPFLAGS=$CPPFLAGS_save - - # --export-dynamic allows exported symbols to be resolved via - # --dlsym and friends. - LDFLAGS="-export-dynamic $LDFLAGS" - else - AC_MSG_WARN([Failed to build GNU libltdl. This usually means that something]) - AC_MSG_WARN([is incorrectly setup with your environment. There may be useful information in]) - AC_MSG_WARN([opal/libltdl/config.log. You can also disable GNU libltdl, which will disable]) - AC_MSG_WARN([dynamic shared object loading, by configuring with --disable-dlopen.]) - AC_MSG_ERROR([Cannot continue]) - fi - CFLAGS=$CFLAGS_save - - OPAL_VAR_SCOPE_POP -])dnl diff --git a/configure.ac b/configure.ac index 713b97f4aed..b05e33b08d7 100644 --- a/configure.ac +++ b/configure.ac @@ -1230,8 +1230,6 @@ fi # a C++ compiler. AS_IF([test "$OMPI_WANT_FORTRAN_BINDINGS" != "1"],[F77=no FC=no]) -LT_CONFIG_LTDL_DIR([opal/libltdl], [subproject]) -LTDL_CONVENIENCE LT_INIT([dlopen win32-dll]) # What's the suffix of shared libraries? Inspired by generated @@ -1268,8 +1266,6 @@ esac AC_SUBST(OPAL_DYN_LIB_PREFIX) AC_SUBST(OPAL_DYN_LIB_SUFFIX) -OPAL_SETUP_LIBLTDL - # Need the libtool binary before the rpathify stuff LT_OUTPUT diff --git a/contrib/nightly/reports/check_devel_headers.pl b/contrib/nightly/reports/check_devel_headers.pl index 65c308d963a..0b14cef51cf 100755 --- a/contrib/nightly/reports/check_devel_headers.pl +++ b/contrib/nightly/reports/check_devel_headers.pl @@ -10,6 +10,7 @@ # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. +# Copyright (c) 2015 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow @@ -90,11 +91,6 @@ sub wanted { elsif ($parts[0] eq "ompi" && $parts[1] eq "mpi" && $parts[2] eq "f90") { return; } - # The only file we want in opal/libltdl is ltdl.h - elsif ($parts[0] eq "opal" && $parts[1] eq "libltdl" && - $name ne "ltdl.h") { - return; - } # The only file we want in opal/event is event.h elsif ($parts[0] eq "opal" && $parts[1] eq "event" && $name ne "event.h") { diff --git a/opal/Makefile.am b/opal/Makefile.am index 72201662981..360474ab0e7 100644 --- a/opal/Makefile.am +++ b/opal/Makefile.am @@ -9,7 +9,7 @@ # University of Stuttgart. All rights reserved. # Copyright (c) 2004-2005 The Regents of the University of California. # All rights reserved. -# Copyright (c) 2009-2014 Cisco Systems, Inc. All rights reserved. +# Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow @@ -19,7 +19,6 @@ SUBDIRS = \ include \ - $(LIBLTDL_SUBDIR) \ asm \ datatype \ etc \ @@ -35,7 +34,6 @@ SUBDIRS = \ # therefore make distclean will fail). DIST_SUBDIRS = \ include \ - $(LIBLTDL_SUBDIR) \ asm \ datatype \ etc \ @@ -49,7 +47,6 @@ DIST_SUBDIRS = \ lib_LTLIBRARIES = lib@OPAL_LIB_PREFIX@open-pal.la lib@OPAL_LIB_PREFIX@open_pal_la_SOURCES = lib@OPAL_LIB_PREFIX@open_pal_la_LIBADD = \ - $(LIBLTDL) \ asm/libasm.la \ datatype/libdatatype.la \ mca/base/libmca_base.la \ @@ -69,11 +66,6 @@ lib@OPAL_LIB_PREFIX@open_pal_la_SOURCES += $(headers) if WANT_INSTALL_HEADERS opaldir = $(opalincludedir)/$(subdir) nobase_opal_HEADERS = $(headers) - -# This is somewhat of a hack -- libltdl is installed by libtoolize, -# and us installing the header here is slightly less kludgey than -# hacking their Makefile.am. -nobase_opal_HEADERS += libltdl/ltdl.h endif include class/Makefile.am