Header-only 和使用 QMake 的静态构建
Header-only and static build with QMake
我正在尝试设置一个简单的 class,它既可以用作 header,也可以与 qmake 一起静态使用。如果构建是静态的,我正在使用 .pro 文件中定义的宏 "STATIC_BUILD" 进行控制。
foo.pro:
TEMPLATE = app
CONFIG += c++11
CONFIG += STATIC_BUILD
STATIC_BUILD {
DEFINES += STATIC_BUILD
}
SOURCES += \
main.cpp
HEADERS += \
foo.h
STATIC_BUILD {
SOURCES += \
foo.cpp
}
foo.h
#ifndef FOO_H
#define FOO_H
#ifndef STATIC_BUILD
#define MY_INLINE inline
#else
#define MY_INLINE
#endif
class Foo {
public:
Foo();
int getI() const;
void setI(int value);
private:
int i;
};
#ifndef STATIC_BUILD
#include "foo.cpp"
#endif
#endif // FOO_H
foo.cpp
#include "foo.h"
MY_INLINE Foo::Foo(){}
MY_INLINE int Foo::getI() const {
return i;
}
MY_INLINE void Foo::setI(int value) {
i = value;
}
main.cpp
#include <iostream>
#include "foo.h"
int main() {
Foo f;
f.setI(3);
std::cout << f.getI() << "\n";
return 0;
}
在 foo.pro 中注释行 "CONFIG += STATIC_BUILD" 并将 class 用作 header 仅按预期工作。
如果我将此项目编译为静态(上面的行未注释),我会为 "Foo" 的成员得到 "undefined reference"。
我注意到,"CONFIG += STATIC_BUILD" 没有评论,而是评论行
#include "foo.cpp"
在 foo.h 中,一切正常(当然,仅适用于静态构建)。
这对我来说没有任何意义,因为 "ifndef" 的目的正是在静态构建中不 "compile" #include。
我做错了什么?
我在 linux 环境中使用带有 gcc 的 Qt 5.11。
这是一个已知的qmake "feature."当它看到:
#include "foo.cpp"
在 header 中(不管它是否是 "evaluated"),它根本不会为 foo.cpp
生成构建规则,所以它不会被构建。不幸的是,Qt 开发人员似乎并不认为这是一个错误,而是一个功能。
解决方法是创建第三个文件(如 foo_incsrc.h
),其中只有一行:
#include "foo.cpp"
并相应地更改您的 foo.h
:
#ifndef STATIC_BUILD
#include "foo_incsrc.h"
#endif
这是一个已知的 QMake 错误,报告了几次:
(警告:第三次错误报告中不必要的攻击性语言)
简而言之,#include
指令中提到的"source file"跳过构建的机制不够聪明,无法考虑#include
指令是否会真正执行(也就是说,它不知道预处理器条件)。
我正在尝试设置一个简单的 class,它既可以用作 header,也可以与 qmake 一起静态使用。如果构建是静态的,我正在使用 .pro 文件中定义的宏 "STATIC_BUILD" 进行控制。
foo.pro:
TEMPLATE = app
CONFIG += c++11
CONFIG += STATIC_BUILD
STATIC_BUILD {
DEFINES += STATIC_BUILD
}
SOURCES += \
main.cpp
HEADERS += \
foo.h
STATIC_BUILD {
SOURCES += \
foo.cpp
}
foo.h
#ifndef FOO_H
#define FOO_H
#ifndef STATIC_BUILD
#define MY_INLINE inline
#else
#define MY_INLINE
#endif
class Foo {
public:
Foo();
int getI() const;
void setI(int value);
private:
int i;
};
#ifndef STATIC_BUILD
#include "foo.cpp"
#endif
#endif // FOO_H
foo.cpp
#include "foo.h"
MY_INLINE Foo::Foo(){}
MY_INLINE int Foo::getI() const {
return i;
}
MY_INLINE void Foo::setI(int value) {
i = value;
}
main.cpp
#include <iostream>
#include "foo.h"
int main() {
Foo f;
f.setI(3);
std::cout << f.getI() << "\n";
return 0;
}
在 foo.pro 中注释行 "CONFIG += STATIC_BUILD" 并将 class 用作 header 仅按预期工作。 如果我将此项目编译为静态(上面的行未注释),我会为 "Foo" 的成员得到 "undefined reference"。
我注意到,"CONFIG += STATIC_BUILD" 没有评论,而是评论行
#include "foo.cpp"
在 foo.h 中,一切正常(当然,仅适用于静态构建)。 这对我来说没有任何意义,因为 "ifndef" 的目的正是在静态构建中不 "compile" #include。
我做错了什么?
我在 linux 环境中使用带有 gcc 的 Qt 5.11。
这是一个已知的qmake "feature."当它看到:
#include "foo.cpp"
在 header 中(不管它是否是 "evaluated"),它根本不会为 foo.cpp
生成构建规则,所以它不会被构建。不幸的是,Qt 开发人员似乎并不认为这是一个错误,而是一个功能。
解决方法是创建第三个文件(如 foo_incsrc.h
),其中只有一行:
#include "foo.cpp"
并相应地更改您的 foo.h
:
#ifndef STATIC_BUILD
#include "foo_incsrc.h"
#endif
这是一个已知的 QMake 错误,报告了几次:
(警告:第三次错误报告中不必要的攻击性语言)
简而言之,#include
指令中提到的"source file"跳过构建的机制不够聪明,无法考虑#include
指令是否会真正执行(也就是说,它不知道预处理器条件)。