diff --git a/Makefile.am b/Makefile.am index 645bfd9..4f746b7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,5 +3,8 @@ ACLOCAL_AMFLAGS = -I m4 pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = easyRNG.pc +if ENABLE_FORTRAN +pkgconfig_DATA += easyRNGf03.pc +endif -EXTRA_DIST = easyRNG.pc.in easyRNG.spec.in meson.build meson_options.txt install_fortran_mod.py +EXTRA_DIST = easyRNG.pc.in easyRNG.spec.in meson.build meson_options.txt install_fortran_mod.py easyRNGf03.pc.in diff --git a/configure.ac b/configure.ac index d7cbcf4..f2588f7 100644 --- a/configure.ac +++ b/configure.ac @@ -5,8 +5,8 @@ AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) AC_CANONICAL_HOST -LIB_CURRENT=0 -LIB_REVISION=1 +LIB_CURRENT=1 +LIB_REVISION=0 LIB_AGE=0 AC_SUBST(LIB_CURRENT) AC_SUBST(LIB_REVISION) @@ -21,7 +21,7 @@ m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) #libtool LT_PREREQ([2.0.0]) -LT_INIT() +LT_INIT([win32-dll disable-static]) AC_PROG_LIBTOOL AC_PROG_CC @@ -48,13 +48,55 @@ AC_PROG_CXX_C_O AX_CXX_COMPILE_STDCXX_11(noext, mandatory) LDFLAGS_EXTRA="" +OS_WINDOWS=0 case "$host" in *mingw*) LDFLAGS_EXTRA+="-no-undefined" + OS_WINDOWS=1 ;; esac AC_SUBST(LDFLAGS_EXTRA) +if test $OS_WINDOWS = 1 ; then + if test x$enable_static = xyes -a x$enable_shared = xyes; then + AC_MSG_ERROR([Can not build both shared and static at the same time on Windows.]) + fi +fi + +# Symbol visibility handling. +# +# Taken from gtksourceview and modified where necessary +HIDDEN_VISIBILITY_CXXFLAGS="" +case "$host" in + *-*-mingw*) + dnl on mingw32 we do -fvisibility=hidden and __declspec(dllexport) + AC_DEFINE([EASYRNG_EXTERN], [__attribute__((visibility("default"))) __declspec(dllexport) extern], + [defines how to decorate public symbols while building]) + HIDDEN_VISIBILITY_CXXFLAGS="-fvisibility=hidden" + ;; + *) + dnl on other compilers, check if we can do -fvisibility=hidden + SAVED_CXXFLAGS="${CXXFLAGS}" + CXXFLAGS="-fvisibility=hidden" + AC_MSG_CHECKING([for -fvisibility=hidden compiler flag]) + AC_LANG_PUSH(C++) + AC_TRY_COMPILE([], [return 0], + AC_MSG_RESULT(yes) + enable_fvisibility_hidden=yes, + AC_MSG_RESULT(no) + enable_fvisibility_hidden=no) + AC_LANG_POP(C++) + CXXFLAGS="${SAVED_CXXFLAGS}" + + AS_IF([test "${enable_fvisibility_hidden}" = "yes"], [ + AC_DEFINE([EASYRNG_EXTERN], [__attribute__((visibility("default"))) extern], + [defines how to decorate public symbols while building]) + HIDDEN_VISIBILITY_CXXFLAGS="-fvisibility=hidden" + ]) + ;; +esac + +AC_SUBST(HIDDEN_VISIBILITY_CXXFLAGS) #check for Fortran support BUILD_FORTRAN=no @@ -136,7 +178,7 @@ AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([docs/Doxyfile])]) -AC_CONFIG_FILES([Makefile src/Makefile tests/Makefile easyRNG.pc docs/Makefile easyRNG.spec]) +AC_CONFIG_FILES([Makefile src/Makefile tests/Makefile easyRNG.pc easyRNGf03.pc docs/Makefile easyRNG.spec]) AC_CONFIG_HEADERS([config.h]) AC_OUTPUT diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 97313a3..3fa1b48 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -848,7 +848,7 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include @@ -1988,7 +1988,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -1996,7 +1996,7 @@ MACRO_EXPANSION = NO # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. @@ -2028,7 +2028,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS +PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS EASYRNG_EXTERN # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/docs/meson.build b/docs/meson.build index c77d3b7..6aa4414 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -7,8 +7,7 @@ doxygen_cdata.set('builddir', meson.current_build_dir()) doxyfile = configure_file(input: 'Doxyfile.in', output: 'Doxyfile', - configuration: doxygen_cdata, - install: false) + configuration: doxygen_cdata) datadir = join_paths(get_option('datadir'), 'doc', 'easyRNG') diff --git a/easyRNG.pc.in b/easyRNG.pc.in index 9aeb358..b549872 100644 --- a/easyRNG.pc.in +++ b/easyRNG.pc.in @@ -2,10 +2,9 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ -with_fortran=@with_fortran@ Name: easyRNG -Description: wrapper around C++11's random number generators for use in C and Fortran +Description: wrapper around C++11's random number generators for use in C Version: @VERSION@ Requires: Conflicts: diff --git a/easyRNGf03.pc.in b/easyRNGf03.pc.in new file mode 100644 index 0000000..ef47c96 --- /dev/null +++ b/easyRNGf03.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: easyRNGf03 +Description: wrapper around C++11's random number generators for use in Fortran +Version: @VERSION@ +Requires: easyRNG +Conflicts: +Libs: -L${libdir} -leasyRNGf03 +Cflags: -I${includedir}/easyRNGf03 diff --git a/meson.build b/meson.build index 2fbf1cc..89f1e68 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('easyRNG', ['c', 'cpp'], version:'1.2', license: 'BSD', default_options: ['cpp_std=c++11']) +project('easyRNG', ['c', 'cpp'], version:'1.2', license: 'BSD', default_options: ['cpp_std=c++11'], meson_version: '>= 0.46.0') # versioning stuff -> maintain compatibility with libtool! # # a) If binary compatibility has been broken (eg removed or changed interfaces) @@ -6,8 +6,8 @@ project('easyRNG', ['c', 'cpp'], version:'1.2', license: 'BSD', default_options: # # b) If interfaces have been changed or added, but binary compatibility has # # been preserved, change to C+1:0:A+1 # # c) If the interface is the same as the previous version, change to C:R+1:A -lib_current = 0 -lib_revision = 1 +lib_current = 1 +lib_revision = 0 lib_age = 0 version = '@0@.@1@.@2@'.format((lib_current - lib_age), lib_age, lib_revision) @@ -45,23 +45,58 @@ ENDSUBROUTINE meson.add_install_script('install_fortran_mod.py') endif +config_h = configuration_data() + +# Detect and set symbol visibility +# Taken from gtksourceview +if get_option('default_library') != 'static' + cpp = meson.get_compiler('cpp') + if host_machine.system() == 'windows' + config_h.set('DLL_EXPORT', true) + if cpp.get_id() == 'msvc' + config_h.set('EASYRNG_EXTERN', '__declspec(dllexport) extern') + elif cpp.has_argument('-fvisibility=hidden') + config_h.set('EASYRNG_EXTERN', '__attribute__((visibility("default"))) __declspec(dllexport) extern') + endif + elif cpp.has_argument('-fvisibility=hidden') + config_h.set('EASYRNG_EXTERN', '__attribute__((visibility("default"))) extern') + endif +endif + +configure_file(output: 'config.h', configuration: config_h) + +rootdir = include_directories('.') + subdir('src') # generate pkg-config file pkgconfig.generate( + easyRNG_lib, filebase: 'easyRNG', name: 'easyRNG', - description: 'wrapper around C++11\'s random number generators for use in C and Fortran', + description: 'wrapper around C++11\'s random number generators for use in C', version: meson.project_version(), libraries: easyRNG_lib, subdirs: 'easyRNG', - variables: ['with_fortran=' + (get_option('with-fortran') ? 'yes' : 'no')], ) +if get_option('with-fortran') + pkgconfig.generate( + easyRNGf03_lib, + filebase: 'easyRNGf03', + name: 'easyRNGf03', + description: 'wrapper around C++11\'s random number generators for use in Fortran', + version: meson.project_version(), + libraries: [easyRNGf03_lib, easyRNG_lib], + subdirs: 'easyRNG', + ) + +endif + # generate RPM SPEC file rpm_config = configuration_data() rpm_config.set('VERSION', meson.project_version()) -configure_file(input: 'easyRNG.spec.in', output: 'easyRNG.spec', configuration: rpm_config, install: false) +configure_file(input: 'easyRNG.spec.in', output: 'easyRNG.spec', configuration: rpm_config) subdir('tests') diff --git a/src/Makefile.am b/src/Makefile.am index e837e96..56d0d85 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,14 +6,17 @@ easyRNGinclude_HEADERS = easy_rng.h easy_randist.h libeasyRNG_la_SOURCES = $(easyRNGinclude_HEADERS) easy_rng.cpp easy_rng_private.h easy_randist.cpp libeasyRNG_la_LDFLAGS = -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ $(LDFLAGS_EXTRA) +libeasyRNG_la_CXXFLAGS = $(HIDDEN_VISIBILITY_CXXFLAGS) if ENABLE_FORTRAN -libeasyRNG_la_SOURCES += easy_rng_f.F90 +lib_LTLIBRARIES += libeasyRNGf03.la +libeasyRNGf03_la_SOURCES = easy_rng_f.F90 nodist_easyRNGinclude_HEADERS = easyrng.mod BUILT_SOURCES = easyrng.mod -libeasyRNG_la_LIBADD = $(FCLIBS) -easyrng.mod: libeasyRNG.la +libeasyRNGf03_la_LIBADD = $(FCLIBS) libeasyRNG.la +libeasyRNGf03_la_LDFLAGS = -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ $(LDFLAGS_EXTRA) +easyrng.mod: libeasyRNGf03.la endif clean-local: diff --git a/src/easy_randist.cpp b/src/easy_randist.cpp index 2a38144..27f5c62 100644 --- a/src/easy_randist.cpp +++ b/src/easy_randist.cpp @@ -28,6 +28,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "easy_randist.h" #include "easy_rng_private.h" #include diff --git a/src/easy_randist.h b/src/easy_randist.h index e9734c3..c887977 100644 --- a/src/easy_randist.h +++ b/src/easy_randist.h @@ -60,6 +60,7 @@ extern "C" { * \param sigma The standard deviation of the normal distribution * \returns A double precision real number, sampled from a normal distribution */ +EASYRNG_EXTERN double easy_ran_gaussian (const easy_rng * r, double sigma); /** Generate double precision real numbers according to a [normal distribution](https://en.wikipedia.org/wiki/Normal_distribution) @@ -69,6 +70,7 @@ double easy_ran_gaussian (const easy_rng * r, double sigma); * \param sigma The standard deviation of the normal distribution * \returns A double precision real number, sampled from a normal distribution */ +EASYRNG_EXTERN double easy_ran_gaussian_ziggurat (const easy_rng * r, double sigma); /** Generate double precision real numbers according to a [normal distribution](https://en.wikipedia.org/wiki/Normal_distribution) @@ -78,6 +80,7 @@ double easy_ran_gaussian_ziggurat (const easy_rng * r, double sigma); * \param sigma The standard deviation of the normal distribution * \returns A double precision real number, sampled from a normal distribution */ +EASYRNG_EXTERN double easy_ran_gaussian_ratio_method (const easy_rng * r, double sigma); /** Generate double precision real numbers according to a [unit normal distribution](https://en.wikipedia.org/wiki/Normal_distribution#Standard_normal_distribution) @@ -89,6 +92,7 @@ double easy_ran_gaussian_ratio_method (const easy_rng * r, double sigma); * \param r The random number generator instance * \returns A double precision real number, sampled from a unit normal distribution */ +EASYRNG_EXTERN double easy_ran_ugaussian (const easy_rng * r); /** Generate double precision real numbers according to a [unit normal distribution](https://en.wikipedia.org/wiki/Normal_distribution#Standard_normal_distribution) @@ -97,6 +101,7 @@ double easy_ran_ugaussian (const easy_rng * r); * \param r The random number generator instance * \returns A double precision real number, sampled from a unit normal distribution */ +EASYRNG_EXTERN double easy_ran_ugaussian_ratio_method (const easy_rng * r); /** Generate double precision random numbers according to an [exponential distribution](https://en.wikipedia.org/wiki/Exponential_distribution) @@ -109,6 +114,7 @@ double easy_ran_ugaussian_ratio_method (const easy_rng * r); * \param mu The inverse rate * \returns A positive double precision real number, sampled from an exponential distribution */ +EASYRNG_EXTERN double easy_ran_exponential (const easy_rng * r, double mu); /** Generate double precision random numbers according to a [Cauchy distribution](https://en.wikipedia.org/wiki/Cauchy_distribution) @@ -121,6 +127,7 @@ double easy_ran_exponential (const easy_rng * r, double mu); * \param a The scale parameter * \returns A double precision real number, sampled from a Cauchy distribution */ +EASYRNG_EXTERN double easy_ran_cauchy (const easy_rng * r, double a); /** Generate double precision random numbers according to a [Gamma distribution](https://en.wikipedia.org/wiki/Gamma_distribution) @@ -134,6 +141,7 @@ double easy_ran_cauchy (const easy_rng * r, double a); * \param theta The scale parameter (must be strictly positive) * \returns A positive double precision real number, sampled from a Gamma distribution */ +EASYRNG_EXTERN double easy_ran_gamma (const easy_rng * r, double k, double theta); /** Generate double precision random numbers according to a [flat distribution](https://en.wikipedia.org/wiki/Uniform_distribution_%28continuous%29) @@ -147,6 +155,7 @@ double easy_ran_gamma (const easy_rng * r, double k, double theta); * \param b The maximum value of the sampling interval * \returns A double precision real number, sampled from a flat distribution */ +EASYRNG_EXTERN double easy_ran_flat (const easy_rng * r, double a, double b); /** Generate double precision random numbers according to a [log-normal distribution](https://en.wikipedia.org/wiki/Log-normal_distribution) @@ -160,6 +169,7 @@ double easy_ran_flat (const easy_rng * r, double a, double b); * \param sigma The scale parameter (must be strictly positive) * \returns A positive double precision real number, sampled from a log-normal distribution */ +EASYRNG_EXTERN double easy_ran_lognormal (const easy_rng * r, double mu, double sigma); /** Generate double precision random numbers according to a [chi-squared distribution](https://en.wikipedia.org/wiki/Chi-squared_distribution) @@ -172,6 +182,7 @@ double easy_ran_lognormal (const easy_rng * r, double mu, double sigma); * \param k The degrees of freedom * \returns A positive double precision real number, sampled from a chi-squared distribution */ +EASYRNG_EXTERN double easy_ran_chisq (const easy_rng * r, double k); /** Generate double precision random numbers according to an [F distribution](https://en.wikipedia.org/wiki/F-distribution) @@ -185,6 +196,7 @@ double easy_ran_chisq (const easy_rng * r, double k); * \param d_2 The second degrees of freedom * \returns A positive double precision real number, sampled from a F-distribution */ +EASYRNG_EXTERN double easy_ran_fdist (const easy_rng * r, double d_1, double d_2); /** Generate double precision random numbers according to a [Student's t-distribution](https://en.wikipedia.org/wiki/Student's_t-distribution) @@ -197,6 +209,7 @@ double easy_ran_fdist (const easy_rng * r, double d_1, double d_2); * \param nu The degrees of freedom * \returns A double precision real number, sampled from a Student's t-distribution */ +EASYRNG_EXTERN double easy_ran_tdist (const easy_rng * r, double nu); /** Generate double precision random numbers according to a [Weibull distribution](https://en.wikipedia.org/wiki/Weibull_distribution) @@ -210,6 +223,7 @@ double easy_ran_tdist (const easy_rng * r, double nu); * \param k The shape parameter * \returns A double precision real number, sampled from a Weibull distribution */ +EASYRNG_EXTERN double easy_ran_weibull (const easy_rng * r, double lambda, double k); // Thought that std::extreme_value_distribution was matching Gumbel Type 1, but that looks incorrect @@ -233,6 +247,7 @@ typedef struct _easy_ran_discrete_t easy_ran_discrete_t; * \returns The lookup table. Pass this variable to easy_ran_discrete() to generate discrete random numbers based on the contents of \c P * \warning The Fortran API drops the \c K argument as the size of the P array can be determined from the variable itself. */ +EASYRNG_EXTERN easy_ran_discrete_t * easy_ran_discrete_preproc (size_t K, const double * P); /** Generate positive integers according to a discrete distribution @@ -241,12 +256,14 @@ easy_ran_discrete_t * easy_ran_discrete_preproc (size_t K, const double * P); * \param g The lookup table * \returns A positive integer, sampled from a discrete distribution */ +EASYRNG_EXTERN size_t easy_ran_discrete (const easy_rng * r, const easy_ran_discrete_t * g); /** Frees the memory associated with a discrete distribution lookup table * * \param g The lookup table */ +EASYRNG_EXTERN void easy_ran_discrete_free (easy_ran_discrete_t * g); /** Generate positive integers according to a [Poisson distribution](https://en.wikipedia.org/wiki/Poisson_distribution) @@ -259,6 +276,7 @@ void easy_ran_discrete_free (easy_ran_discrete_t * g); * \param lambda The average number of events in an interval * \returns A positive integer, sampled from a Poisson distribution */ +EASYRNG_EXTERN unsigned int easy_ran_poisson (const easy_rng * r, double lambda); /** Generate zeroes and ones according to a [Bernoulli distribution](https://en.wikipedia.org/wiki/Bernoulli_distribution) @@ -271,6 +289,7 @@ unsigned int easy_ran_poisson (const easy_rng * r, double lambda); * \param p The success probability * \returns 0 or 1, sampled from a Bernoulli distribution */ +EASYRNG_EXTERN unsigned int easy_ran_bernoulli (const easy_rng * r, double p); /** Generate positive integers according to a [binomial distribution](https://en.wikipedia.org/wiki/Binomial_distribution) @@ -284,6 +303,7 @@ unsigned int easy_ran_bernoulli (const easy_rng * r, double p); * \param n The number of trials * \returns A positive integer, sampled from a binomial distribution */ +EASYRNG_EXTERN unsigned int easy_ran_binomial (const easy_rng * r, double p, unsigned int n); /** Generate positive integers according to a [negative binomial distribution](https://en.wikipedia.org/wiki/Negative_binomial_distribution) @@ -298,6 +318,7 @@ unsigned int easy_ran_binomial (const easy_rng * r, double p, unsigned int n); * \param n The number of successful trials * \returns A positive integer, sampled from a negative binomial distribution */ +EASYRNG_EXTERN unsigned int easy_ran_negative_binomial (const easy_rng * r, double p, unsigned int n); /** Generate positive integers according to a [geometric distribution](https://en.wikipedia.org/wiki/Geometric_distribution) @@ -310,6 +331,7 @@ unsigned int easy_ran_negative_binomial (const easy_rng * r, double p, unsigned * \param p The success probability for each trial * \returns A positive integer, sampled from a geometric distribution */ +EASYRNG_EXTERN unsigned int easy_ran_geometric (const easy_rng * r, double p); #ifdef __cplusplus diff --git a/src/easy_rng.cpp b/src/easy_rng.cpp index 557307d..d6c8c53 100644 --- a/src/easy_rng.cpp +++ b/src/easy_rng.cpp @@ -28,6 +28,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" +#include "easy_rng.h" #include "easy_rng_private.h" #include #include diff --git a/src/easy_rng.h b/src/easy_rng.h index 6f3558b..9950326 100644 --- a/src/easy_rng.h +++ b/src/easy_rng.h @@ -53,6 +53,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern "C" { #endif +#ifndef EASYRNG_EXTERN + #define EASYRNG_EXTERN extern +#endif + #ifndef DOXYGEN_SHOULD_SKIP_THIS struct _easy_rng; #endif @@ -79,6 +83,7 @@ typedef struct { * \param T The type of a random number generator to use * \returns A newly allocated random number generator that has been seeded with the default seed. */ +EASYRNG_EXTERN easy_rng * easy_rng_alloc (const easy_rng_type * T); /** Set the current seed. @@ -87,6 +92,7 @@ easy_rng * easy_rng_alloc (const easy_rng_type * T); * \param r The random number generator instance * \param s The new seed */ +EASYRNG_EXTERN void easy_rng_set (const easy_rng * r, unsigned long int s); /** Frees the memory associated with a random number generator instance @@ -94,6 +100,7 @@ void easy_rng_set (const easy_rng * r, unsigned long int s); * After calling this function, do not attempt to pass the random number generator instance to any other function! * \param r The random number generator instance */ +EASYRNG_EXTERN void easy_rng_free (easy_rng * r); /** Generate a random, uniformally distributed unsigned long int. @@ -102,6 +109,7 @@ void easy_rng_free (easy_rng * r); * \param r The random number generator instance * \returns A unsigned long int */ +EASYRNG_EXTERN unsigned long int easy_rng_get (const easy_rng * r); /** Generate a random, uniformally distributed double precision floating point number in the interval [0,1) @@ -110,6 +118,7 @@ unsigned long int easy_rng_get (const easy_rng * r); * \param r The random number generator instance * \returns A double precision floating point number between 0 and 1 */ +EASYRNG_EXTERN double easy_rng_uniform (const easy_rng * r); /** Generate a random, uniformally distributed double precision floating point number in the interval (0,1) @@ -118,6 +127,7 @@ double easy_rng_uniform (const easy_rng * r); * \param r The random number generator instance * \returns A double precision floating point number between 0 and 1 */ +EASYRNG_EXTERN double easy_rng_uniform_pos (const easy_rng * r); /** Generate a random, uniformally distributed unsigned long int in the interval [0, n) @@ -127,6 +137,7 @@ double easy_rng_uniform_pos (const easy_rng * r); * \param n The upper limit (exclusive) of the generated values * \returns An unsigned long int between 0 and n-1 */ +EASYRNG_EXTERN unsigned long int easy_rng_uniform_int (const easy_rng * r, unsigned long int n); /** Return the name of the random generator type as string @@ -135,6 +146,7 @@ unsigned long int easy_rng_uniform_int (const easy_rng * r, unsigned long int n) * \param r The random number generator instance * \returns The name of the random generator type */ +EASYRNG_EXTERN const char * easy_rng_name (const easy_rng * r); /** Return the maximum value that can be returned by easy_rng_get() @@ -143,6 +155,7 @@ const char * easy_rng_name (const easy_rng * r); * \param r The random number generator instance * \returns The maximum value that can be returned by easy_rng_get() */ +EASYRNG_EXTERN unsigned long int easy_rng_max (const easy_rng * r); /** Return the minimum value that can be returned by easy_rng_get() @@ -151,6 +164,7 @@ unsigned long int easy_rng_max (const easy_rng * r); * \param r The random number generator instance * \returns The minimum value that can be returned by easy_rng_get() */ +EASYRNG_EXTERN unsigned long int easy_rng_min (const easy_rng * r); /* Not going to happen... @@ -164,6 +178,7 @@ size_t easy_rng_size (const easy_rng * r); * This array must not be freed! * \returns the array */ +EASYRNG_EXTERN const easy_rng_type ** easy_rng_types_setup (void); /** Set the default seed and/or default random number generator type @@ -173,6 +188,7 @@ const easy_rng_type ** easy_rng_types_setup (void); * to instantiate and seed a new random number generator. * \returns easy_rng_default */ +EASYRNG_EXTERN const easy_rng_type * easy_rng_env_setup (void); /** Copy the state of a random number generator \c src into another random number generator \c dest @@ -183,6 +199,7 @@ const easy_rng_type * easy_rng_env_setup (void); * \param src The source random number generator * \returns 0 on success, -1 on failure */ +EASYRNG_EXTERN int easy_rng_memcpy (easy_rng * dest, const easy_rng * src); /** Creates an exact copy of the random number generator \c c. @@ -192,6 +209,7 @@ int easy_rng_memcpy (easy_rng * dest, const easy_rng * src); * \param r The random number generator instance * \returns The cloned random number generator */ +EASYRNG_EXTERN easy_rng * easy_rng_clone (const easy_rng * r); /** Test if two random number generator instances are identical @@ -201,6 +219,7 @@ easy_rng * easy_rng_clone (const easy_rng * r); * \param rb The second random number generator instance * \returns 1 if equal, 0 otherwise */ +EASYRNG_EXTERN int easy_rng_equal(const easy_rng * ra, const easy_rng *rb); /** Write the state of the random number generator to a file @@ -210,6 +229,7 @@ int easy_rng_equal(const easy_rng * ra, const easy_rng *rb); * \param r The random number generator instance * \returns 0 on success, -1 otherwise */ +EASYRNG_EXTERN int easy_rng_fwrite (FILE * stream, const easy_rng * r); /** Read the state of the random number generator from a file @@ -219,63 +239,75 @@ int easy_rng_fwrite (FILE * stream, const easy_rng * r); * \param r The random number generator instance * \returns 0 on success, -1 otherwise */ +EASYRNG_EXTERN int easy_rng_fread (FILE * stream, easy_rng * r); /** Linear congruential engine, discovered in 1969 by Lewis, Goodman and Miller, adopted as "Minimal standard" in 1988 by Park and Miller */ -extern const easy_rng_type *easy_rng_minstd_rand0; +EASYRNG_EXTERN +const easy_rng_type *easy_rng_minstd_rand0; /** Linear congruential engine, newer "Minimum standard", recommended by Park, Miller, and Stockmeyer in 1993 */ -extern const easy_rng_type *easy_rng_minstd_rand; +EASYRNG_EXTERN +const easy_rng_type *easy_rng_minstd_rand; /** 32-bit Mersenne Twister engine, published by Matsumoto and Nishimura, 1998 * * This is also the type that easy_rng_default maps to, unless overridden by EASY_RNG_TYPE and easy_rng_env_setup() is called. * In case of doubt, always use this type. */ -extern const easy_rng_type *easy_rng_mt19937; +EASYRNG_EXTERN +const easy_rng_type *easy_rng_mt19937; /** 64-bit Mersenne Twister engine, published by Matsumoto and Nishimura, 2000 * */ -extern const easy_rng_type *easy_rng_mt19937_64; +EASYRNG_EXTERN +const easy_rng_type *easy_rng_mt19937_64; /** A subtract with carry engine * */ -extern const easy_rng_type *easy_rng_ranlux24_base; +EASYRNG_EXTERN +const easy_rng_type *easy_rng_ranlux24_base; /** A subtract with carry engine * */ -extern const easy_rng_type *easy_rng_ranlux48_base; +EASYRNG_EXTERN +const easy_rng_type *easy_rng_ranlux48_base; /** A subtract with carry engine, that discards a certain amount of data produced by the base engine. * */ -extern const easy_rng_type *easy_rng_ranlux24; +EASYRNG_EXTERN +const easy_rng_type *easy_rng_ranlux24; /** A subtract with carry engine, that discards a certain amount of data produced by the base engine. * */ -extern const easy_rng_type *easy_rng_ranlux48; +EASYRNG_EXTERN +const easy_rng_type *easy_rng_ranlux48; /** A shuffle order engine * */ -extern const easy_rng_type *easy_rng_knuth_b; +EASYRNG_EXTERN +const easy_rng_type *easy_rng_knuth_b; /** The default random number generator type * * Maps by default to easy_rng_mt19937 */ -extern const easy_rng_type *easy_rng_default; +EASYRNG_EXTERN +const easy_rng_type *easy_rng_default; /** The seed that will be used to initialize newly allocated random number generators * */ -extern unsigned long int easy_rng_default_seed; +EASYRNG_EXTERN +unsigned long int easy_rng_default_seed; #ifdef __cplusplus diff --git a/src/easy_rng_f.F90 b/src/easy_rng_f.F90 index 67d046e..936c321 100644 --- a/src/easy_rng_f.F90 +++ b/src/easy_rng_f.F90 @@ -49,9 +49,9 @@ MODULE easyRNG IMPLICIT NONE -TYPE, BIND(C) :: easy_rng_type +TYPE :: easy_rng_type PRIVATE - TYPE (C_PTR) :: rng_type + INTEGER (C_INT) :: id ENDTYPE easy_rng_type TYPE :: easy_rng @@ -64,23 +64,42 @@ MODULE easyRNG TYPE (C_PTR) :: ran_discrete_t ENDTYPE -TYPE (easy_rng_type), BIND(C, NAME='easy_rng_minstd_rand0') :: easy_rng_minstd_rand0 -TYPE (easy_rng_type), BIND(C, NAME='easy_rng_minstd_rand') :: easy_rng_minstd_rand -TYPE (easy_rng_type), BIND(C, NAME='easy_rng_mt19937') :: easy_rng_mt19937 -TYPE (easy_rng_type), BIND(C, NAME='easy_rng_mt19937_64') :: easy_rng_mt19937_64 -TYPE (easy_rng_type), BIND(C, NAME='easy_rng_ranlux24_base') :: easy_rng_ranlux24_base -TYPE (easy_rng_type), BIND(C, NAME='easy_rng_ranlux48_base') :: easy_rng_ranlux48_base -TYPE (easy_rng_type), BIND(C, NAME='easy_rng_ranlux24') :: easy_rng_ranlux24 -TYPE (easy_rng_type), BIND(C, NAME='easy_rng_ranlux48') :: easy_rng_ranlux48 -TYPE (easy_rng_type), BIND(C, NAME='easy_rng_knuth_b') :: easy_rng_knuth_b -TYPE (easy_rng_type), BIND(C, NAME='easy_rng_default') :: easy_rng_default +TYPE (C_PTR), BIND(C, NAME='easy_rng_minstd_rand0') :: easy_rng_minstd_rand0_c +TYPE (C_PTR), BIND(C, NAME='easy_rng_minstd_rand') :: easy_rng_minstd_rand_c +TYPE (C_PTR), BIND(C, NAME='easy_rng_mt19937') :: easy_rng_mt19937_c +TYPE (C_PTR), BIND(C, NAME='easy_rng_mt19937_64') :: easy_rng_mt19937_64_c +TYPE (C_PTR), BIND(C, NAME='easy_rng_ranlux24_base') :: easy_rng_ranlux24_base_c +TYPE (C_PTR), BIND(C, NAME='easy_rng_ranlux48_base') :: easy_rng_ranlux48_base_c +TYPE (C_PTR), BIND(C, NAME='easy_rng_ranlux24') :: easy_rng_ranlux24_c +TYPE (C_PTR), BIND(C, NAME='easy_rng_ranlux48') :: easy_rng_ranlux48_c +TYPE (C_PTR), BIND(C, NAME='easy_rng_knuth_b') :: easy_rng_knuth_b_c +TYPE (C_PTR), BIND(C, NAME='easy_rng_default') :: easy_rng_default_c + +TYPE (easy_rng_type), PARAMETER :: easy_rng_minstd_rand0 = easy_rng_type(0) +TYPE (easy_rng_type), PARAMETER :: easy_rng_minstd_rand = easy_rng_type(1) +TYPE (easy_rng_type), PARAMETER :: easy_rng_mt19937 = easy_rng_type(2) +TYPE (easy_rng_type), PARAMETER :: easy_rng_mt19937_64 = easy_rng_type(3) +TYPE (easy_rng_type), PARAMETER :: easy_rng_ranlux24_base = easy_rng_type(4) +TYPE (easy_rng_type), PARAMETER :: easy_rng_ranlux48_base = easy_rng_type(5) +TYPE (easy_rng_type), PARAMETER :: easy_rng_ranlux24 = easy_rng_type(6) +TYPE (easy_rng_type), PARAMETER :: easy_rng_ranlux48 = easy_rng_type(7) +TYPE (easy_rng_type), PARAMETER :: easy_rng_knuth_b = easy_rng_type(8) +TYPE (easy_rng_type), PARAMETER :: easy_rng_default = easy_rng_type(9) CONTAINS !easy_rng * easy_rng_alloc (const easy_rng_type * T); +#ifdef _WIN32 +#ifdef __GFORTRAN__ +!GCC$ ATTRIBUTES DLLEXPORT:: easy_rng_alloc +#else +!DEC$ ATTRIBUTES DLLEXPORT:: easy_rng_alloc +#endif +#endif FUNCTION easy_rng_alloc(T) RESULT(rv) TYPE (easy_rng_type), INTENT(IN) :: T TYPE (easy_rng) :: rv + TYPE (C_PTR) :: T_c INTERFACE FUNCTION easy_rng_alloc_c(T) BIND(C, NAME='easy_rng_alloc') RESULT(rv) @@ -89,9 +108,43 @@ FUNCTION easy_rng_alloc_c(T) BIND(C, NAME='easy_rng_alloc') RESULT(rv) TYPE (C_PTR), VALUE, INTENT(IN) :: T TYPE (C_PTR) :: rv ENDFUNCTION easy_rng_alloc_c - ENDINTERFACE - rv%rng = easy_rng_alloc_c(T%rng_type) + SUBROUTINE easy_exit(status) BIND(C, NAME='exit') + USE, INTRINSIC :: ISO_C_BINDING + IMPLICIT NONE + INTEGER (C_INT), VALUE, INTENT(IN) :: status + ENDSUBROUTINE easy_exit + ENDINTERFACE + + WRITE (output_unit, '(A,I3)') 'type id: ', T%id + + SELECT CASE (T%id) + CASE (0) + T_c = easy_rng_minstd_rand0_c + CASE (1) + T_c = easy_rng_minstd_rand_c + CASE (2) + T_c = easy_rng_mt19937_c + CASE (3) + T_c = easy_rng_mt19937_64_c + CASE (4) + T_c = easy_rng_ranlux24_base_c + CASE (5) + T_c = easy_rng_ranlux48_base_c + CASE (6) + T_c = easy_rng_ranlux24_c + CASE (7) + T_c = easy_rng_ranlux48_c + CASE (8) + T_c = easy_rng_knuth_b_c + CASE (9) + T_c = easy_rng_default_c + CASE DEFAULT + WRITE (error_unit, '(A)') 'easy_rng_alloc: Invalid RNG type detected' + CALL easy_exit(1) + ENDSELECT + + rv%rng = easy_rng_alloc_c(T_c) ENDFUNCTION easy_rng_alloc @@ -283,39 +336,27 @@ FUNCTION easy_rng_min_c(r) BIND(C, NAME='easy_rng_min') RESULT(rv) !const easy_rng_type ** easy_rng_types_setup (void); FUNCTION easy_rng_types_setup() RESULT(RV) - TYPE (C_PTR) :: types_c - TYPE (C_PTR), POINTER, DIMENSION(:) :: types_c_all TYPE (easy_rng_type), POINTER, DIMENSION(:) :: rv INTEGER :: length, i - INTERFACE - FUNCTION easy_rng_types_setup_c() BIND(C, NAME='easy_rng_types_setup') RESULT(rv) - USE, INTRINSIC :: ISO_C_BINDING - IMPLICIT NONE - TYPE (C_PTR) :: rv - ENDFUNCTION easy_rng_types_setup_c - ENDINTERFACE - - length = 0 - - types_c = easy_rng_types_setup_c() - - ! start by assuming a very, very long array - CALL C_F_POINTER(types_c, types_c_all, [1024]) - DO i=1, 1024 - IF (.NOT. C_ASSOCIATED(types_c_all(i))) THEN - EXIT - ENDIF - length = length + 1 - ENDDO - - CALL C_F_POINTER(types_c, rv, [length]) + ALLOCATE(rv(10)) + rv(1) = easy_rng_minstd_rand0 + rv(2) = easy_rng_minstd_rand + rv(3) = easy_rng_mt19937 + rv(4) = easy_rng_mt19937_64 + rv(5) = easy_rng_ranlux24_base + rv(6) = easy_rng_ranlux48_base + rv(7) = easy_rng_ranlux24 + rv(8) = easy_rng_ranlux48 + rv(9) = easy_rng_knuth_b + rv(10) = easy_rng_default ENDFUNCTION easy_rng_types_setup !const easy_rng_type * easy_rng_env_setup (void); FUNCTION easy_rng_env_setup() RESULT(rv) TYPE (easy_rng_type) :: rv + TYPE (C_PTR) :: rv_c INTERFACE FUNCTION easy_rng_env_setup_c() BIND(C, NAME='easy_rng_env_setup') RESULT(rv) @@ -323,9 +364,41 @@ FUNCTION easy_rng_env_setup_c() BIND(C, NAME='easy_rng_env_setup') RESULT(rv) IMPLICIT NONE TYPE (C_PTR) :: rv ENDFUNCTION easy_rng_env_setup_c - ENDINTERFACE - rv%rng_type = easy_rng_env_setup_c() + SUBROUTINE easy_exit(status) BIND(C, NAME='exit') + USE, INTRINSIC :: ISO_C_BINDING + IMPLICIT NONE + INTEGER (C_INT), VALUE, INTENT(IN) :: status + ENDSUBROUTINE easy_exit + ENDINTERFACE + + rv_c = easy_rng_env_setup_c() + + IF (C_ASSOCIATED(rv_c, easy_rng_minstd_rand0_c)) THEN + rv%id = 0 + ELSEIF (C_ASSOCIATED(rv_c, easy_rng_minstd_rand_c)) THEN + rv%id = 1 + ELSEIF (C_ASSOCIATED(rv_c, easy_rng_mt19937_c)) THEN + rv%id = 2 + ELSEIF (C_ASSOCIATED(rv_c, easy_rng_mt19937_64_c)) THEN + rv%id = 3 + ELSEIF (C_ASSOCIATED(rv_c, easy_rng_ranlux24_base_c)) THEN + rv%id = 4 + ELSEIF (C_ASSOCIATED(rv_c, easy_rng_ranlux48_base_c)) THEN + rv%id = 5 + ELSEIF (C_ASSOCIATED(rv_c, easy_rng_ranlux24_c)) THEN + rv%id = 6 + ELSEIF (C_ASSOCIATED(rv_c, easy_rng_ranlux48_c)) THEN + rv%id = 7 + ELSEIF (C_ASSOCIATED(rv_c, easy_rng_knuth_b_c)) THEN + rv%id = 8 + ELSEIF (C_ASSOCIATED(rv_c, easy_rng_default_c)) THEN + rv%id = 9 + ELSE + WRITE (error_unit, '(A)') 'easy_rng_setup: unknown RNG type returned' + CALL easy_exit(1) + ENDIF + ENDFUNCTION easy_rng_env_setup diff --git a/src/meson.build b/src/meson.build index 0a3a224..53fd157 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,14 +4,18 @@ private_headers = files('easy_rng_private.h') sources = files('easy_rng.cpp', 'easy_randist.cpp') -if get_option('with-fortran') - sources += files('easy_rng_f.F90') -endif - install_headers(headers, subdir: 'easyRNG') easyRNG_sources = headers + private_headers + sources -easyRNG_lib = library('easyRNG', easyRNG_sources, version: version, darwin_versions: darwin_versions, install: true) +easyRNG_lib = library('easyRNG', easyRNG_sources, version: version, darwin_versions: darwin_versions, install: true, include_directories: rootdir) easyRNG_lib_dep = declare_dependency(link_with: easyRNG_lib, include_directories: include_directories('.')) + +if get_option('with-fortran') + easyRNGf03_sources = files('easy_rng_f.F90') + + easyRNGf03_lib = library('easyRNGf03', easyRNGf03_sources, version: version, darwin_versions: darwin_versions, install: true, dependencies: easyRNG_lib_dep) + + easyRNGf03_lib_dep = declare_dependency(link_with: easyRNGf03_lib, dependencies: easyRNG_lib_dep, include_directories: include_directories('.')) +endif diff --git a/tests/Makefile.am b/tests/Makefile.am index 604cf99..dd724c6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -21,19 +21,19 @@ if ENABLE_FORTRAN check_PROGRAMS += test4 test4_SOURCES = test4.F90 test4_FCFLAGS = -I$(top_builddir)/src -test4_LDADD = ../src/libeasyRNG.la +test4_LDADD = ../src/libeasyRNGf03.la if ENABLE_FGSL_TEST check_PROGRAMS += test5 test5_SOURCES = test5.F90 test5_FCFLAGS = -I$(top_builddir)/src $(fgsl_CFLAGS) -test5_LDADD = ../src/libeasyRNG.la $(fgsl_LIBS) -lm +test5_LDADD = ../src/libeasyRNGf03.la ../src/libeasyRNG.la $(fgsl_LIBS) -lm endif check_PROGRAMS += test6 test6_SOURCES = test6.F90 test6_FCFLAGS = -I$(top_builddir)/src -test6_LDADD = ../src/libeasyRNG.la -lm +test6_LDADD = ../src/libeasyRNGf03.la ../src/libeasyRNG.la -lm endif TESTS = $(check_PROGRAMS) diff --git a/tests/meson.build b/tests/meson.build index f333264..e432d39 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -10,14 +10,14 @@ test3 = executable('test3', 'test3.c', dependencies: easyRNG_lib_dep, install: f test('test3', test3, timeout: 300) if get_option('with-fortran') - test4 = executable('test4', 'test4.F90', dependencies: easyRNG_lib_dep, install: false) + test4 = executable('test4', 'test4.F90', dependencies: easyRNGf03_lib_dep, install: false) test('test4', test4) if fgsl_dep.found() - test5 = executable('test5', 'test5.F90', dependencies: [easyRNG_lib_dep, fgsl_dep], install: false) + test5 = executable('test5', 'test5.F90', dependencies: [easyRNGf03_lib_dep, fgsl_dep], install: false) test('test5', test5) endif - test6 = executable('test6', 'test6.F90', dependencies: easyRNG_lib_dep, install: false) + test6 = executable('test6', 'test6.F90', dependencies: easyRNGf03_lib_dep, install: false) test('test6', test6, timeout: 300) endif diff --git a/tests/test4.F90 b/tests/test4.F90 index c3dd192..7899340 100644 --- a/tests/test4.F90 +++ b/tests/test4.F90 @@ -55,4 +55,6 @@ SUBROUTINE easy_exit(exit_status) BIND(C, NAME='exit') ENDDO +DEALLOCATE(all_types) + ENDPROGRAM test4