简体   繁体   中英

Header-only and static build with QMake

I am trying to set up a simple class that can be used both as a header only and static with qmake. I am contolling if the build is static using a macro "STATIC_BUILD" defined in the .pro file.

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;
}

Commenting the line "CONFIG += STATIC_BUILD" in foo.pro and using the class as header only works as expected. If I compile this project as static (with the line above not commented) I get "undefined reference" for members of "Foo".

I noticed that, with "CONFIG += STATIC_BUILD" not commented and commenting instead the line

#include "foo.cpp"

in foo.h, everything works correctly (only for the static build, of course). This does not make any sense to me because the "ifndef" has excactly the purpose to do not "compile" the #include in the static build.

What am I doing wrong?

I am using Qt 5.11 with gcc in a linux environment.

This is a known QMake bug, reported a few times:

(warning: unnecessary offensive language in the third bug report)

In short, the mechanism that skips build for a "source file" found to be mentioned in an #include directive is not smart enough to consider whether the #include directive will actually be executed (that is, it doesn't know about preprocessor conditionals).

This is a known qmake "feature." When it sees:

#include "foo.cpp"

in the header (regardless of whether it would be "evaluated" or not), it simply doesn't generate build rules for foo.cpp , so it's not getting built. Unfortunately, it seems the Qt developers don't view this as a bug, but as a feature.

The workaround is to create a third file (like foo_incsrc.h ) that only has a single line in it:

#include "foo.cpp"

and change your foo.h accordingly:

#ifndef STATIC_BUILD
#include "foo_incsrc.h"
#endif

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM