cmake - 从函数调用find_package而不是全局范围时的奇怪副作用

时间:2016-04-19 16:55:29

标签: c++ qt cmake

我在这里有一个非常简单的cmake项目,它构建了一个Qt应用程序。

使用:

find_packageCMakeLists.txt

中从全球范围调用

CMakeLists.txt

cmake_minimum_required(VERSION 3.2.2)
project(gui CXX)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")

find_package(Qt5Widgets REQUIRED)

qt5_wrap_cpp         (moc_output message.h)
add_executable       (gui main.cpp ${moc_output})
target_link_libraries(gui Qt5::Widgets)

如上所列,代码构建成功。

$ make
[ 25%] Generating moc_message.cpp
Scanning dependencies of target gui
[ 50%] Building CXX object CMakeFiles/gui.dir/main.cpp.o
[ 75%] Building CXX object CMakeFiles/gui.dir/moc_message.cpp.o
[100%] Linking CXX executable gui
[100%] Built target gui

不起作用:

find_packageCMakeLists.txt

中的功能范围调用

但是,如果我将find_package的调用更改为函数内:

CMakeLists.txt

cmake_minimum_required(VERSION 3.2.2)
project(gui CXX)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")

function(load_qt)
    find_package(Qt5Widgets REQUIRED)
endfunction()

load_qt() # this is the only change - find_package called from function load_qt

qt5_wrap_cpp         (moc_output message.h)
add_executable       (gui main.cpp ${moc_output})
target_link_libraries(gui Qt5::Widgets)

代码不再编译。

$ make
 [ 25%] Generating moc_message.cpp
 make[2]: execvp: /.../build/moc_message.cpp_parameters: Permission denied
 make[2]: *** [moc_message.cpp] Error 127
 make[1]: *** [CMakeFiles/gui.dir/all] Error 2
 make: *** [all] Error 2

问题:

  • 为什么会这样?
  • 有没有办法有条件调用find_package,例如:仅当用户调用我的函数时?

完整源代码:

main.cpp

#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QPushButton>
#include "message.h"

class App
{
public:
    App(int& argc, char** argv)
        : app(argc, argv)
    { }

    int exec()
    {
        QMainWindow* window = new QMainWindow;
        QWidget*     widget = new QWidget;
        QVBoxLayout* layout = new QVBoxLayout;
        QPushButton* button = new QPushButton("go");
        Message*     msg    = new Message;

        window->setCentralWidget(widget);
        widget->setLayout(layout);
        layout->addWidget(button);

        QObject::connect(button, &QPushButton::clicked, msg, &Message::onGo);

        window->show();
        return app.exec();
    }

    QApplication app;
};

int main(int argc, char** argv)
{
    return App(argc, argv).exec();
}

message.h

#include <QMessageBox>
#include <QObject>

class Message : public QObject
{
    Q_OBJECT
public slots:
    void onGo()
    {
        QMessageBox(
            QMessageBox::Icon::Information,
            "Hello",
            "World",
            QMessageBox::StandardButton::NoButton,
            nullptr).exec();
    }
};

CMakeLists.txt

cmake_minimum_required (VERSION 3.2.2)
project (gui CXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")

function(load_qt)
    find_package(Qt5Widgets REQUIRED)
endfunction()

# this doesn't work
# load_qt()

# this does work
find_package(Qt5Widgets REQUIRED)

qt5_wrap_cpp         (moc_output message.h)
add_executable       (gui main.cpp ${moc_output})
target_link_libraries(gui Qt5::Widgets)

1 个答案:

答案 0 :(得分:3)

此问题的根本原因是functions 创建新范围

来自文档:

  

函数打开一个新范围:有关详细信息,请参阅set(var PARENT_SCOPE)。

另一方面,

Macros在父范围内运作。

因此,要解决此问题,请将load_qt()更改为宏:

<强> CMakeLists.txt

cmake_minimum_required(VERSION 3.2.2)
project(gui CXX)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")

# note here, load_qt is now a macro rather than a function
macro(load_qt)
    find_package(Qt5Widgets REQUIRED)
endmacro()

load_qt()

qt5_wrap_cpp         (moc_output message.h)
add_executable       (gui main.cpp ${moc_output})
target_link_libraries(gui Qt5::Widgets)