Skip to content

Multiple definitions when including Stan headers in several source files #311

@rgiordan

Description

@rgiordan

Summary:

Stan headers cause multiple definition errors when included in several source files that are linked together in a library.

Description:

If the Stan headers are included in several source files that are compiled separately and then linked, the compiler fails with multiple definition errors. I am a C++ novice, but I believe this is because non-inline functions are being instantiated in the header files (e.g. print_mat_size).

Reproducible Steps:

A minimal example to reproduce can be found in this repo. In short, it has two cpp files that each instantiate templates using Stan variables. They can be successfully compiled into object files, but the linker fails with multiple definition errors.

// source1.hpp:
# ifndef SOURCE1_H
# define SOURCE1_H

#include <boost/math/special_functions/digamma.hpp>
#include <boost/math/special_functions/gamma.hpp>

using boost::math::lgamma;
using boost::math::digamma;

# include <stan/math.hpp>
# include "stan/math/fwd/scal.hpp"

using var = stan::math::var;
using fvar = stan::math::fvar<var>;

template <typename T> T multivariate_lgamma(T x, int p) {
  T result = log(M_PI) * p * (p - 1.0) / 4.0;
  for (int i = 1; i <= p; i++) {
    result += lgamma(x + 0.5 * (1 - (double)i));
  }
  return result;
}

extern template double multivariate_lgamma(double x, int p);
extern template var multivariate_lgamma(var x, int p);
extern template fvar multivariate_lgamma(fvar x, int p);

# endif

// source1.cpp:
# include "source1.hpp"
# include <stan/math.hpp>
# include <stan/math/fwd/scal.hpp>

using var = stan::math::var;
using fvar = stan::math::fvar<var>;

template double multivariate_lgamma(double x, int p);
template var multivariate_lgamma(var x, int p);
template fvar multivariate_lgamma(fvar x, int p);


// source1.hpp:
# ifndef SOURCE2_H
# define SOURCE2_H

#include <boost/math/special_functions/digamma.hpp>
#include <boost/math/special_functions/gamma.hpp>

using boost::math::lgamma;
using boost::math::digamma;

# include <stan/math.hpp>
# include "stan/math/fwd/scal.hpp"

using var = stan::math::var;
using fvar = stan::math::fvar<var>;

template <typename T> T multivariate_digamma(T x, int p) {
  T result = 0.0;
  for (int i = 1; i <= p; i++) {
    result += digamma(x + 0.5 * (1 - (double)i));
  }
  return result;
}

extern template double multivariate_digamma(double x, int p);
extern template var multivariate_digamma(var x, int p);
extern template fvar multivariate_digamma(fvar x, int p);

# endif

// source2.cpp:
# include "source2.hpp"
# include <stan/math.hpp>
# include <stan/math/fwd/scal.hpp>

using var = stan::math::var;
using fvar = stan::math::fvar<var>;

template double multivariate_digamma(double x, int p);
template var multivariate_digamma(var x, int p);
template fvar multivariate_digamma(fvar x, int p);

Current Output:

The linker fails with errors like this:

[ 33%] Building CXX object CMakeFiles/StanHeaderExample.dir/source2.cpp.o
Linking CXX shared library libStanHeaderExample.so
CMakeFiles/StanHeaderExample.dir/source2.cpp.o: In function `stan::math::print_mat_size(int, std::ostream&)':
source2.cpp:(.text+0x1390): multiple definition of `stan::math::print_mat_size(int, std::ostream&)'
CMakeFiles/StanHeaderExample.dir/source1.cpp.o:source1.cpp:(.text+0x12c0): first defined here
CMakeFiles/StanHeaderExample.dir/source2.cpp.o: In function `stan::math::csr_u_to_z(std::vector<int, std::allocator<int> > const&, int)':
source2.cpp:(.text+0x13c0): multiple definition of `stan::math::csr_u_to_z(std::vector<int, std::allocator<int> > const&, int)'
CMakeFiles/StanHeaderExample.dir/source1.cpp.o:source1.cpp:(.text+0x12f0): first defined here
... and so on.

Expected Output:

A compiled shared library with templates instantiated with Stan types.

Additional Information:

Provide any additional information here.

Current Version:

v2.9.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions