Cách chỉ định các thư mục đầu ra Gỡ lỗi / Phát hành khác nhau trong tệp QMake .pro


106

Tôi có một dự án Qt và tôi muốn xuất các tệp biên dịch bên ngoài cây nguồn.

Tôi hiện có cấu trúc thư mục sau:

/
|_/build
|_/mylib
  |_/include
  |_/src
  |_/resources

Tùy thuộc vào cấu hình (gỡ lỗi / phát hành), tôi sẽ muốn xuất các tệp kết quả bên trong thư mục xây dựng dưới thư mục xây dựng / gỡ lỗi hoặc xây dựng / phát hành.

Làm cách nào tôi có thể làm điều đó bằng cách sử dụng tệp .pro?


Cách Qt xử lý gỡ lỗi và phát hành các bản dựng nội bộ đã thay đổi theo thời gian. Vì vậy, chúng tôi đã phát hiện ra rằng các chuyển đổi hoạt động trước đây giữa gỡ lỗi và phát hành đã bị hỏng trong các phiên bản sau. Xem giải pháp của tôi hoạt động trên tất cả các nền tảng và trên tất cả các phiên bản Qt cho đến nay. stackoverflow.com/questions/32046181/…
adlag

2
Vì đây là một câu hỏi cũ, nên chỉ ra rằng có những câu trả lời tốt hơn với số phiếu bầu ít hơn nhiều.
wardw 22/09/18

Câu trả lời:


5

Câu trả lời ngắn gọn là: bạn không .

Bạn nên chạy qmaketheo sau maketrong bất kỳ thư mục xây dựng nào bạn muốn xây dựng. Vì vậy, hãy chạy nó một lần trong một debugthư mục, một lần trong một releasethư mục.

Đó là cách mà bất kỳ ai xây dựng dự án của bạn đều mong đợi nó hoạt động và đó là cách chính Qt được thiết lập để xây dựng, đó cũng là cách Qt Creator mong đợi .protệp của bạn hoạt động: nó chỉ bắt đầu qmakevà sau đó makenằm trong thư mục xây dựng cho cấu hình đã chọn của mục tiêu.

Nếu bạn muốn tạo các thư mục này và thực hiện hai (hoặc nhiều) bản dựng trong chúng, bạn sẽ cần một tệp trang điểm cấp cao nhất, có thể được tạo từ tệp dự án cấp cao nhất thông qua qmake.

Không có gì lạ khi có nhiều hơn hai cấu hình bản dựng, vì vậy bạn không cần thiết phải tự cam kết chỉ phân biệt giữa bản dựng và bản phát hành; bạn có thể có các bản dựng với các mức tối ưu hóa khác nhau, v.v. Việc phân đôi gỡ lỗi / phát hành tốt nhất là nên để yên.


151

Đối với dự án Qt của tôi, tôi sử dụng lược đồ này trong tệp * .pro:

HEADERS += src/dialogs.h
SOURCES += src/main.cpp \
           src/dialogs.cpp

Release:DESTDIR = release
Release:OBJECTS_DIR = release/.obj
Release:MOC_DIR = release/.moc
Release:RCC_DIR = release/.rcc
Release:UI_DIR = release/.ui

Debug:DESTDIR = debug
Debug:OBJECTS_DIR = debug/.obj
Debug:MOC_DIR = debug/.moc
Debug:RCC_DIR = debug/.rcc
Debug:UI_DIR = debug/.ui

Nó đơn giản, nhưng tốt đẹp! :)


18
Đúng thứ tôi cần! Và một lưu ý: Để làm cho mọi việc dễ dàng hơn để chuyển xung quanh, chỉ xác định bạn DESTDIRs có điều kiện, và sau đó sử dụng giá trị đó trên những nẻo đường khác của bạn: OBJECTS_DIR = $${DESTDIR}/.obj. Chúc mừng!
Xavier Holt

4
Tâm trí giải thích cách này được sử dụng / nó làm gì? Nó dường như không có hiệu lực khi tôi thực hiện nó. chỉnh sửa: nếu tôi thay đổi Debug thành debug (chữ thường) thì nó hoạt động. Tôi nghi ngờ đây là một thứ phân biệt chữ hoa chữ thường của windows vs unix.
notlesh,

9
Tôi đã bình chọn nó vì nó hoạt động trên Windows. Trên Linux (Ubuntu 15.04, Qt 5.5.0), tôi phải thay đổi Debugthành debugReleasechuyển sang release.
Jepessen

Cái gì? Rất nhiều để đa nền tảng? @Jepessen ??
Nils

2
Điều này chỉ hoạt động khi bạn chỉ có bản phát hành hoặc gỡ lỗi trong CONFIG. Nếu cả hai đều ở trong cấu hình, cấu hình sau sẽ được sử dụng.
weeska

52

Để thay đổi thư mục cho dll / exe đích, hãy sử dụng điều này trong tệp chuyên nghiệp của bạn:

CONFIG(debug, debug|release) {
    DESTDIR = build/debug
} else {
    DESTDIR = build/release
}

Bạn cũng có thể muốn thay đổi thư mục cho các mục tiêu xây dựng khác như tệp đối tượng và tệp moc (kiểm tra tham chiếu biến qmake để biết chi tiết hoặc tham chiếu hàm qmake CONFIG () ).


5
Nhưng tôi thấy việc đưa $$ OUT_PWD vào trong này sẽ đẹp hơn nhiều, vì vậy DESTDIR = $$ OUT_PWD / debug
Ivo

1
@Ivo: À! Cảm ơn bạn! Tôi đã tìm khắp nơi để tìm biến nào chứa đường dẫn đó! : D
Cameron

1
Sau đó, bạn có thể thêm các dòng như: OBJECTS_DIR = $$DESTDIR/.obj MOC_DIR = $$DESTDIR/.moc RCC_DIR = $$DESTDIR/.qrc UI_DIR = $$DESTDIR/.ui CONFIG()lần lượt ra để giải quyết một số vấn đề của việc sử dụng release:debug:
Carson Ip

Câu trả lời này hoạt động tốt hơn câu trả lời đã chọn. Phần đã chọn hoạt động, nhưng nếu cả gỡ lỗi và bản phát hành được định cấu hình, thì khối cài đặt thứ hai vẫn còn.
Paulo Carvalho

42

Tôi có một cách tiếp cận nhỏ gọn hơn:

release: DESTDIR = build/release
debug:   DESTDIR = build/debug

OBJECTS_DIR = $$DESTDIR/.obj
MOC_DIR = $$DESTDIR/.moc
RCC_DIR = $$DESTDIR/.qrc
UI_DIR = $$DESTDIR/.ui

2
Câu trả lời của bạn là cách gần đây hơn để đặt đầu ra của trình biên dịch trong thư mục riêng biệt.
SIFE

1
bạn đã thử điều này gần đây cho cả gỡ lỗi và phát hành? đầu ra bản dựng của tôi dường như luôn kết thúc trong thư mục phát hành, bất kể cấu hình nào; hành vi qmake / Qt Creator có thể đã thay đổi kể từ khi bạn gửi câu trả lời này mặc dù ...
ssc

1
Cố gắng thêm "CONFIG - = debug" vào các đối số bổ sung của qmake ở chế độ Phát hành
Xin chào W

17

Cách chính xác để thực hiện việc này như sau (cảm ơn Nhóm hỗ trợ QT):

CONFIG(debug, debug|release) {
    DESTDIR = build/debug
}
CONFIG(release, debug|release) {
    DESTDIR = build/release
}

OBJECTS_DIR = $$DESTDIR/.obj
MOC_DIR = $$DESTDIR/.moc
RCC_DIR = $$DESTDIR/.qrc
UI_DIR = $$DESTDIR/.u

Thông tin thêm tại đây: https://wiki.qt.io/Qt_project_org_faq#What_does_the_syntax_CONFIG.28debug.2Cdebug.7Crelease.29_mean_.3F_What_does_the_1st_argument_specify_and_similarly_what_is_the_2nd_.3F


13

Tôi sử dụng cùng một phương pháp do chalup đề xuất,

ParentDirectory = <your directory>

RCC_DIR = "$$ParentDirectory\Build\RCCFiles"
UI_DIR = "$$ParentDirectory\Build\UICFiles"
MOC_DIR = "$$ParentDirectory\Build\MOCFiles"
OBJECTS_DIR = "$$ParentDirectory\Build\ObjFiles"

CONFIG(debug, debug|release) { 
    DESTDIR = "$$ParentDirectory\debug"
}
CONFIG(release, debug|release) { 
    DESTDIR = "$$ParentDirectory\release"
}

12

Câu hỏi cũ, nhưng vẫn có giá trị một câu trả lời cập nhật. Ngày nay, người ta thường làm những gì Qt Creator làm khi sử dụng các bản dựng bóng (chúng được bật theo mặc định khi mở một dự án mới).

Đối với mỗi mục tiêu và kiểu xây dựng khác nhau, quyền qmakeđược chạy với các đối số bên phải trong một thư mục xây dựng khác nhau. Sau đó, điều đó chỉ được xây dựng với đơn giản make.

Vì vậy, cấu trúc thư mục tưởng tượng có thể trông như thế này.

/
|_/build-mylib-qt5-mingw32-debug
|_/build-mylib-qt5-mingw32-release
|_/build-mylib-qt4-msvc2010-debug
|_/build-mylib-qt4-msvc2010-release
|_/build-mylib-qt5-arm-debug
|_/build-mylib-qt5-arm-release
|_/mylib
  |_/include
  |_/src
  |_/resources

Và điều ngẫu nhiên là, a qmakeđược chạy trong thư mục xây dựng:

cd build-mylib-XXXX
/path/to/right/qmake ../mylib/mylib.pro CONFIG+=buildtype ...

Sau đó, nó tạo các tệp makefiles trong thư mục xây dựng, và sau đó makesẽ tạo các tệp trong đó. Không có nguy cơ các phiên bản khác nhau bị trộn lẫn, miễn là qmake không bao giờ được chạy trong thư mục nguồn (nếu có, tốt hơn hãy dọn dẹp nó thật tốt!).

Và khi được thực hiện như vậy, .protệp từ câu trả lời hiện được chấp nhận thậm chí còn đơn giản hơn:

HEADERS += src/dialogs.h
SOURCES += src/main.cpp \
           src/dialogs.cpp

Hoạt động tốt cho một dự án, nhưng nếu bạn có một dự án và một thư viện thì sao? Sau đó, bạn cần một cách phụ thuộc vào kiểu xây dựng để bao gồm các tính năng mặc định của thư viện.
Adversus

@Adversus Tôi không chắc ý bạn chính xác là gì, nhưng có lẽ biến Qmake $(OUT_PWD)là giải pháp?
hyde

Khi tôi áp dụng câu hỏi của mình vào ví dụ của bạn, nó sẽ trở thành: cách sạch nhất để ứng dụng nhận được là mylibgì? Tôi muốn nếu có một cách "duyên dáng" để làm điều này, tôi không thấy cách nào khác ngoài việc sử dụng các kỹ thuật từ các câu trả lời khác: sử dụng loại xây dựng và cấu hình để điền LIBSvào một cách thông minh, vô hiệu hóa lợi thế của việc tạo bóng.
Adversus

@Adversus Nếu mylib là dự án phụ trong cùng một dự án cấp cao nhất, tôi thường sẽ thêm tệp mylib.pri và đặt mọi thứ mà các dự án phụ khác cần ở đó, sử dụng các biến Qmake để luôn có đường dẫn ngay, ngay cả khi đó là bản dựng bóng. Sau đó, các tệp .pro phụ khác sẽ đơn giản cóinclude(../mylib/mylib.pri)
hyde

cảm ơn, đó là những gì tôi đang làm bây giờ, sẽ rất tốt nếu có một giải pháp mà việc này được tự động xử lý, như khi bạn có một dự án với các dự án con trong cmake và sau đó có thể dễ dàng tạo ra các- xây dựng nguồn của toàn bộ cây.
Adversus

3

Nó cũng hữu ích khi có một tên hơi khác cho tệp thực thi đầu ra. Bạn không thể sử dụng một cái gì đó như:

release: Target = ProgramName
debug: Target = ProgramName_d

Tại sao nó không hoạt động là không rõ ràng, nhưng nó không. Nhưng:

CONFIG(debug, debug|release) {
    TARGET = ProgramName
} else {
    TARGET = ProgramName_d
}

Điều này hoạt động miễn là CONFIG +=dòng đứng trước nó.


1

Phiên bản mới của Qt Creator cũng có tùy chọn xây dựng "hồ sơ" giữa gỡ lỗi và phát hành. Đây là cách tôi phát hiện ra điều đó:

CONFIG(debug, debug|release) {  DEFINES += DEBUG_MODE }
else:CONFIG(force_debug_info) { DEFINES += PROFILE_MODE }
else {                          DEFINES += RELEASE_MODE }

0

1. Tìm Gỡ lỗi / Phát hành trong CONFIG

Nhận hiện tại (gỡ lỗi | phát hành).

specified_configs=$$find(CONFIG, "\b(debug|release)\b")
build_subdir=$$last(specified_configs)

(Có thể là nhiều, vì vậy chỉ giữ lại chỉ định cuối cùng trong bản dựng):

2. Đặt DESTDIR

Sử dụng nó có tên phụ xây dựng

DESTDIR = $$PWD/build/$$build_subdir

0

Đây là Makefile của tôi cho các thư mục đầu ra gỡ lỗi / phát hành khác nhau. Makefile này đã được thử nghiệm thành công trên Ubuntu linux. Nó sẽ hoạt động trơn tru trên Windows miễn là Mingw-w64 được cài đặt đúng cách.

ifeq ($(OS),Windows_NT)
    ObjExt=obj
    mkdir_CMD=mkdir
    rm_CMD=rmdir /S /Q
else
    ObjExt=o
    mkdir_CMD=mkdir -p
    rm_CMD=rm -rf
endif

CC     =gcc
CFLAGS =-Wall -ansi
LD     =gcc

OutRootDir=.
DebugDir  =Debug
ReleaseDir=Release


INSTDIR =./bin
INCLUDE =.

SrcFiles=$(wildcard *.c)
EXEC_main=myapp

OBJ_C_Debug   =$(patsubst %.c,  $(OutRootDir)/$(DebugDir)/%.$(ObjExt),$(SrcFiles))
OBJ_C_Release =$(patsubst %.c,  $(OutRootDir)/$(ReleaseDir)/%.$(ObjExt),$(SrcFiles))

.PHONY: Release Debug cleanDebug cleanRelease clean

# Target specific variables
release: CFLAGS += -O -DNDEBUG
debug:   CFLAGS += -g

################################################
#Callable Targets
release: $(OutRootDir)/$(ReleaseDir)/$(EXEC_main)
debug:   $(OutRootDir)/$(DebugDir)/$(EXEC_main)

cleanDebug:
    -$(rm_CMD) "$(OutRootDir)/$(DebugDir)"
    @echo cleanDebug done

cleanRelease:
    -$(rm_CMD) "$(OutRootDir)/$(ReleaseDir)"
    @echo cleanRelease done

clean: cleanDebug cleanRelease
################################################

# Pattern Rules
# Multiple targets cannot be used with pattern rules [https://www.gnu.org/software/make/manual/html_node/Multiple-Targets.html]
$(OutRootDir)/$(ReleaseDir)/%.$(ObjExt): %.c | $(OutRootDir)/$(ReleaseDir)
    $(CC) -I$(INCLUDE) $(CFLAGS) -c $< -o"$@"

$(OutRootDir)/$(DebugDir)/%.$(ObjExt):   %.c | $(OutRootDir)/$(DebugDir)
    $(CC) -I$(INCLUDE) $(CFLAGS) -c $< -o"$@"

# Create output directory
$(OutRootDir)/$(ReleaseDir) $(OutRootDir)/$(DebugDir) $(INSTDIR):
    -$(mkdir_CMD) $@

# Create the executable
# Multiple targets [https://www.gnu.org/software/make/manual/html_node/Multiple-Targets.html]
$(OutRootDir)/$(ReleaseDir)/$(EXEC_main): $(OBJ_C_Release)
$(OutRootDir)/$(DebugDir)/$(EXEC_main):   $(OBJ_C_Debug)
$(OutRootDir)/$(ReleaseDir)/$(EXEC_main) $(OutRootDir)/$(DebugDir)/$(EXEC_main):
    $(LD) $^ -o$@
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.