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指令是否会真正执行(也就是说,它不知道预处理器条件)。