诊断多重定义错误
Diagnose a multiple definition error
我有一个库 QPhiX,我想用一个大型应用程序 Chroma 对其进行编译。这两个库都有其他依赖项,这是一个相当复杂的东西,大约有一百万行。 QPhiX 已编译干净,我已将其安装到 ~/local-jureca
.
在编译 Chroma 的过程中,Intel C++ version 17 compiler 报错如下:
../../lib/libchroma.a(syssolver_mdagm_aggregate.o): In function `QPhiX::CommsUtils::sumDouble(double*)':
syssolver_mdagm_aggregate.cc:(.text+0x180): multiple definition of `QPhiX::CommsUtils::sumDouble(double*)'
../../lib/libchroma.a(syssolver_linop_aggregate.o):syssolver_linop_aggregate.cc:(.text+0x1d0): first defined here
编译器调用是这样的,长长的一行我已经手工分解了。一些标志被复制是因为 configure
拾取所用库的标志并将它们破坏到 CXXFLAGS
.
/usr/local/software/jureca/Stages/2016b/software/impi/2017.0.098-iccifort-2017.0.098-GCC-5.4.0/bin64/mpiicpc \
-I/homec/hbn28/hbn28e/Sources/chroma/mainprogs/main \
-I/homec/hbn28/hbn28e/Sources/chroma/lib \
-I../../lib \
-O2 \
-Wall \
-fopenmp \
--std=c++11 \
-I/homec/hbn28/hbn28e/local-jureca/include \
-I/homec/hbn28/hbn28e/local-jureca/include/libxml2 \
-I/usr/local/software/jureca/Stages/2016b/software/GMP/6.1.1-iccifort-2017.0.098-GCC-5.4.0/include \
-O2 \
-Wall \
-fopenmp \
-I/homec/hbn28/hbn28e/local-jureca/include \
-O2 \
-Wall \
-fopenmp \
-L../../lib \
-L/homec/hbn28/hbn28e/local-jureca/lib \
-L/usr/local/software/jureca/Stages/2016b/software/GMP/6.1.1-iccifort-2017.0.098-GCC-5.4.0/lib \
-L/homec/hbn28/hbn28e/local-jureca/lib \
-L../../other_libs/qdp-lapack/lib
-o cfgtransf \
cfgtransf.o \
-lchroma \
-lqdp \
-lXPathReader \
-lxmlWriter \
-lqio \
-llime \
-L/homec/hbn28/hbn28e/local-jureca/lib \
-lxml2 \
-lm \
-lqmp \
-lqmp \
-lintrin \
-lfiledb \
-lfilehash \
-lgmp \
-lqphix_solver \
-lqdp-lapack
我查看了函数 QPhiX::CommsUtils::sumDouble(double*)
的定义位置。在 Chroma 中,没有一次使用此功能。因此,错误在 QPhiX 中,但没有人注意到,因为那里没有文件包含头文件 qphix/include/qphix/comm.h
。精简后,此文件位于:
namespace QPhiX {
#ifndef QPHIX_DO_COMMS
namespace CommsUtils {
void sumDouble(double *d) {}
}
#else
// I see a multiple definition error of `sumDouble` when compiling Chroma. I
// suspect that somehow both flags are passed. Therefore check that only one of
// the mutually exclusive flags is given. Perhaps it would be even better to
// use a `#else` here.
#if defined(QPHIX_FAKE_COMMS) && defined(QPHIX_QMP_COMMS)
#error \
"You must specify QPHIX_FAKE_COMMS xor QPHIX_QMP_COMMS when specifying QPHIX_DO_COMMS."
#endif
#ifdef QPHIX_FAKE_COMMS
namespace CommsUtils {
void sumDouble(double *d) {}
};
#endif // QPHIX_FAKE_COMMS
#ifdef QPHIX_QMP_COMMS
namespace CommsUtils {
void sumDouble(double *d) { QMP_sum_double(d); };
};
#endif // QPHIX_QMP_COMMS
#endif // ifndef QPHIX_DO_COMMS
}; // Namespace
预处理器分支看起来只能在该文件中激活一个定义。如果 QPHIX_FAKE_COMMS
和 QPHIX_QMP_COMMS
都由构建系统提供,则 #error
应该已被激活。
这两条错误消息都是在 libchroma.a
中引起的,那一定是编译 Chroma 的中间构建步骤。这两个定义在不同的目标文件中(syssolver_mdagm_aggregate.o
和 syssolver_linop_aggregate.o
),但是匹配的 C++ 源文件都不包含函数定义,它们都只包含 QPhiX 头文件。那里定义了函数 sumDouble
。
这里发生了什么? sumDouble
的两个定义是否会成为一个问题,即使这两种情况下的三个变体相同?或者这是否意味着两个 Chroma 源文件包含设置了不同预处理器标志的 qphix/include/qphix/comm.h
?
我该如何解决这个问题?只是明确地在 QPhiX 中制作所有有问题的功能 inline
?他们似乎只委托给 QDP++ 库,所以内联就好了。
可能是我运气不好,QPhiX 和 Chroma 的 devel
分支不能一起工作,但是 master
也不行。所以我再次想知道我做错了什么,假设开发这个软件的人可以很好地编译它。
如果在头文件中定义函数,需要在头文件前加上inline。
否则如果多个文件包含它,当link人尝试link时,它会发现多个定义存在并报告多个定义错误(如果有内联,linker会选择其中一个)。
我有一个库 QPhiX,我想用一个大型应用程序 Chroma 对其进行编译。这两个库都有其他依赖项,这是一个相当复杂的东西,大约有一百万行。 QPhiX 已编译干净,我已将其安装到 ~/local-jureca
.
在编译 Chroma 的过程中,Intel C++ version 17 compiler 报错如下:
../../lib/libchroma.a(syssolver_mdagm_aggregate.o): In function `QPhiX::CommsUtils::sumDouble(double*)':
syssolver_mdagm_aggregate.cc:(.text+0x180): multiple definition of `QPhiX::CommsUtils::sumDouble(double*)'
../../lib/libchroma.a(syssolver_linop_aggregate.o):syssolver_linop_aggregate.cc:(.text+0x1d0): first defined here
编译器调用是这样的,长长的一行我已经手工分解了。一些标志被复制是因为 configure
拾取所用库的标志并将它们破坏到 CXXFLAGS
.
/usr/local/software/jureca/Stages/2016b/software/impi/2017.0.098-iccifort-2017.0.098-GCC-5.4.0/bin64/mpiicpc \
-I/homec/hbn28/hbn28e/Sources/chroma/mainprogs/main \
-I/homec/hbn28/hbn28e/Sources/chroma/lib \
-I../../lib \
-O2 \
-Wall \
-fopenmp \
--std=c++11 \
-I/homec/hbn28/hbn28e/local-jureca/include \
-I/homec/hbn28/hbn28e/local-jureca/include/libxml2 \
-I/usr/local/software/jureca/Stages/2016b/software/GMP/6.1.1-iccifort-2017.0.098-GCC-5.4.0/include \
-O2 \
-Wall \
-fopenmp \
-I/homec/hbn28/hbn28e/local-jureca/include \
-O2 \
-Wall \
-fopenmp \
-L../../lib \
-L/homec/hbn28/hbn28e/local-jureca/lib \
-L/usr/local/software/jureca/Stages/2016b/software/GMP/6.1.1-iccifort-2017.0.098-GCC-5.4.0/lib \
-L/homec/hbn28/hbn28e/local-jureca/lib \
-L../../other_libs/qdp-lapack/lib
-o cfgtransf \
cfgtransf.o \
-lchroma \
-lqdp \
-lXPathReader \
-lxmlWriter \
-lqio \
-llime \
-L/homec/hbn28/hbn28e/local-jureca/lib \
-lxml2 \
-lm \
-lqmp \
-lqmp \
-lintrin \
-lfiledb \
-lfilehash \
-lgmp \
-lqphix_solver \
-lqdp-lapack
我查看了函数 QPhiX::CommsUtils::sumDouble(double*)
的定义位置。在 Chroma 中,没有一次使用此功能。因此,错误在 QPhiX 中,但没有人注意到,因为那里没有文件包含头文件 qphix/include/qphix/comm.h
。精简后,此文件位于:
namespace QPhiX {
#ifndef QPHIX_DO_COMMS
namespace CommsUtils {
void sumDouble(double *d) {}
}
#else
// I see a multiple definition error of `sumDouble` when compiling Chroma. I
// suspect that somehow both flags are passed. Therefore check that only one of
// the mutually exclusive flags is given. Perhaps it would be even better to
// use a `#else` here.
#if defined(QPHIX_FAKE_COMMS) && defined(QPHIX_QMP_COMMS)
#error \
"You must specify QPHIX_FAKE_COMMS xor QPHIX_QMP_COMMS when specifying QPHIX_DO_COMMS."
#endif
#ifdef QPHIX_FAKE_COMMS
namespace CommsUtils {
void sumDouble(double *d) {}
};
#endif // QPHIX_FAKE_COMMS
#ifdef QPHIX_QMP_COMMS
namespace CommsUtils {
void sumDouble(double *d) { QMP_sum_double(d); };
};
#endif // QPHIX_QMP_COMMS
#endif // ifndef QPHIX_DO_COMMS
}; // Namespace
预处理器分支看起来只能在该文件中激活一个定义。如果 QPHIX_FAKE_COMMS
和 QPHIX_QMP_COMMS
都由构建系统提供,则 #error
应该已被激活。
这两条错误消息都是在 libchroma.a
中引起的,那一定是编译 Chroma 的中间构建步骤。这两个定义在不同的目标文件中(syssolver_mdagm_aggregate.o
和 syssolver_linop_aggregate.o
),但是匹配的 C++ 源文件都不包含函数定义,它们都只包含 QPhiX 头文件。那里定义了函数 sumDouble
。
这里发生了什么? sumDouble
的两个定义是否会成为一个问题,即使这两种情况下的三个变体相同?或者这是否意味着两个 Chroma 源文件包含设置了不同预处理器标志的 qphix/include/qphix/comm.h
?
我该如何解决这个问题?只是明确地在 QPhiX 中制作所有有问题的功能 inline
?他们似乎只委托给 QDP++ 库,所以内联就好了。
可能是我运气不好,QPhiX 和 Chroma 的 devel
分支不能一起工作,但是 master
也不行。所以我再次想知道我做错了什么,假设开发这个软件的人可以很好地编译它。
如果在头文件中定义函数,需要在头文件前加上inline。
否则如果多个文件包含它,当link人尝试link时,它会发现多个定义存在并报告多个定义错误(如果有内联,linker会选择其中一个)。