You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt项目用Ninja构建时修改UI文件后cpp.obj未重新生成问题

Qt项目Ninja构建:修改UI后obj文件不重新编译的问题

我用Ninja+MSVC2019+CMake构建Qt项目,现在碰到个问题:修改UI文件后重新构建,ui_mainwindow.h会重新生成,但mainwindow.cpp.obj不会跟着编译,导致界面修改不生效。之前用NMake+MSVC2019没这问题,但NMake太慢才换的Ninja,现在得找出Ninja不重新生成obj的原因。


相关代码文件

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(NinjaTest VERSION 0.1 LANGUAGES CXX)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)

set(PROJECT_SOURCES
        main.cpp
        mainwindow.cpp
        mainwindow.h
        mainwindow.ui
)


qt_add_executable(NinjaTest
        MANUAL_FINALIZATION
        ${PROJECT_SOURCES}
    )

target_link_libraries(NinjaTest PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)

set_target_properties(NinjaTest PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)

install(TARGETS NinjaTest
    BUNDLE DESTINATION .
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

if(QT_VERSION_MAJOR EQUAL 6)
    qt_finalize_executable(NinjaTest)
endif()

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "./ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>260</x>
      <y>260</y>
      <width>63</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>COUCOU</string>
    </property>
   </widget>
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>280</x>
      <y>80</y>
      <width>83</width>
      <height>29</height>
     </rect>
    </property>
    <property name="text">
     <string>PushButton</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>25</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

问题分析与解决办法

核心原因

CMake的AUTOUIC机制默认会把ui_mainwindow.h生成在构建目录的自动生成文件夹(比如build/CMakeFiles/NinjaTest.dir/autogen/include/),但你的mainwindow.cpp里写的是#include "./ui_mainwindow.h"——这个相对路径会让编译器优先去源码目录找文件,而非构建目录里的最新生成版。

Ninja的依赖检查比NMake严格得多:它只会追踪代码里显式写的依赖路径,发现源码目录里的ui_mainwindow.h没变化,就不会触发mainwindow.cpp.obj的重新编译。而NMake依赖检查的松散性恰好绕过了这个问题。

解决步骤

  1. 修改头文件包含路径
    把mainwindow.cpp里的#include "./ui_mainwindow.h"改成#include "ui_mainwindow.h",去掉./前缀。这样编译器会按照CMake配置的包含路径,优先找到构建目录里的自动生成文件,Ninja也能正确追踪到ui_mainwindow.h和mainwindow.cpp的依赖关系。

  2. 清理构建目录重新生成
    删除整个构建目录,重新运行CMake配置命令(比如cmake -G Ninja -S . -B build),再用ninja -C build构建。之后修改UI文件,就能触发mainwindow.cpp的重新编译,界面修改会正常生效。

  3. 可选:自定义AUTOUIC生成目录(进阶)
    如果需要指定生成文件的位置,可在CMakeLists.txt中添加:

    set(CMAKE_AUTOUIC_OUTPUT_DIR ${CMAKE_BINARY_DIR}/ui)
    target_include_directories(NinjaTest PRIVATE ${CMAKE_BINARY_DIR}/ui)
    

    不过默认配置下,只要去掉./前缀就足够解决问题,无需额外配置。


内容的提问来源于stack exchange,提问作者Fdo7

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:34:51