Qmake için Hayati Bir Kılavuz
Yayınlanan: 2022-03-11Tanıtım
qmake , farklı platformlarda oluşturma sürecini basitleştiren, Qt kitaplığıyla birlikte gönderilen bir yapı sistemi aracıdır. CMake ve Qbs'den farklı olarak, qmake en başından beri Qt'nin bir parçasıydı ve “yerel” bir araç olarak kabul edilecektir. Söylemeye gerek yok, Qt'nin varsayılan IDE'si — Qt Creator — kutudan çıktığı haliyle en iyi qmake desteğine sahiptir. Evet, orada yeni bir proje için CMake ve Qbs derleme sistemlerini de seçebilirsiniz, ancak bunlar o kadar iyi entegre değil. Qt Creator'daki CMake desteğinin zaman içinde iyileştirilmesi muhtemeldir ve bu, bu kılavuzun özellikle CMake'i hedefleyen ikinci baskısını yayınlamak için iyi bir neden olacaktır. Qt Creator kullanmayı düşünmüyorsanız bile, halk kütüphaneleri veya eklentiler oluşturuyorsanız qmake'i ikinci bir derleme sistemi olarak düşünebilirsiniz. Neredeyse tüm üçüncü taraf Qt tabanlı kitaplıklar veya eklentiler, qmake tabanlı projelere sorunsuz bir şekilde entegre olmak için kullanılan qmake dosyalarını sağlar. Yalnızca birkaçı ikili yapılandırma sağlar, örneğin qmake ve CMake. Aşağıdakiler sizin için geçerliyse qmake kullanmayı tercih edebilirsiniz:
- Platformlar arası Qt tabanlı bir proje oluşturuyorsunuz
- Qt Creator IDE ve özelliklerinin çoğunu kullanıyorsunuz
- Diğer qmake projeleri tarafından kullanılacak bağımsız bir kitaplık/eklenti oluşturuyorsunuz
Bu kılavuz, en kullanışlı qmake özelliklerini açıklar ve her biri için gerçek dünyadan örnekler sunar. Qt'de yeni olan okuyucular bu kılavuzu Qt'nin inşa sistemi için bir öğretici olarak kullanabilirler. Qt geliştiricileri, yeni bir projeye başlarken bunu bir yemek kitabı olarak değerlendirebilir veya bazı özellikleri düşük etki ile mevcut projelerden herhangi birine seçerek uygulayabilir.
Temel Qmake Kullanımı
qmake belirtimi .pro
(“proje”) dosyalarına yazılır. Bu, mümkün olan en basit .pro
dosyasına bir örnektir:
SOURCES = hello.cpp
Varsayılan olarak bu, hello.cpp
tek kaynak kod dosyasından bir yürütülebilir dosya oluşturacak bir Makefile
oluşturacaktır.
İkiliyi oluşturmak için (bu durumda yürütülebilir), önce bir Makefile oluşturmak için qmake'i çalıştırmanız ve ardından hedefi oluşturmak için make
(veya nmake
veya araç zincirinize bağlı olarak mingw32-make
) yapmanız gerekir.
Özetle, bir qmake belirtimi, isteğe bağlı kontrol akışı ifadeleriyle karıştırılmış bir değişken tanımları listesinden başka bir şey değildir. Her değişken genel olarak bir dizi dizi içerir. Kontrol akışı deyimleri, diğer qmake belirtim dosyalarını, kontrol koşullu bölümlerini ve hatta çağrı fonksiyonlarını dahil etmenize izin verir.
Değişkenlerin Sözdizimini Anlamak
Mevcut qmake projelerini öğrenirken, farklı değişkenlere nasıl başvurulabileceğine şaşırabilirsiniz: \(VAR,\){VAR} veya $$(VAR) …
Kuralları benimserken bu mini hile sayfasını kullanın:
-
VAR = value
ata -
VAR += value
VAR listesine değer ekle -
VAR -= value
kaldır -
$$VAR
veya$${VAR}
qmake çalışırken VAR değerini alır -
$(VAR)
Makefile (qmake değil) çalışırken Ortam VAR'ın içeriği -
$$(VAR)
qmake (Makefile değil) çalışırken Ortam VAR'ın içeriği
Ortak Şablonlar
qmake değişkenlerinin tam listesi spesifikasyonda bulunabilir: http://doc.qt.io/qt-5/qmake-variable-reference.html
Projeler için birkaç yaygın şablonu gözden geçirelim:
# Windows application TEMPLATE = app CONFIG += windows # Shared library (.so or .dll) TEMPLATE = lib CONFIG += shared # Static library (.a or .lib) TEMPLATE = lib CONFIG += static # Console application TEMPLATE = app CONFIG += console
Tüm kaynak kod dosyalarınızı listelemek için SOURCES += … ve HEADERS += … ekleyin ve işiniz bitti.
Şimdiye kadar çok temel şablonları inceledik. Daha karmaşık projeler genellikle birbirine bağımlı birkaç alt proje içerir. Bunu qmake ile nasıl yöneteceğimizi görelim.
alt projeler
En yaygın kullanım durumu, bir veya birkaç kitaplık ve test projesiyle birlikte gönderilen bir uygulamadır. Aşağıdaki yapıyı göz önünde bulundurun:
/project ../library ..../include ../library-tests ../application
Açıkçası, her şeyi bir kerede inşa edebilmek istiyoruz, bunun gibi:
cd project qmake && make
Bu amaca ulaşmak için /project
klasörü altında bir qmake proje dosyasına ihtiyacımız var:
TEMPLATE = subdirs SUBDIRS = library library-tests application library-tests.depends = library application.depends = library
NOT: CONFIG += ordered
order öğesinin kullanılması kötü bir uygulama olarak kabul edilir; bunun yerine .depends
kullanmayı tercih edin.
Bu belirtim, diğer hedefler buna bağlı olduğundan, önce qmake'e bir kitaplık alt projesi oluşturma talimatı verir. Ardından, bu ikisi bağımlı olduğundan, library-tests
ve uygulamayı keyfi bir sırada oluşturabilir.
Kitaplıkları Bağlama
Yukarıdaki örnekte, uygulamaya bağlanması gereken bir kitaplığımız var. C/C++'da bu, birkaç şeyi daha yapılandırmamız gerektiği anlamına gelir:
- #include yönergeleri için arama yolları sağlamak için
-I
belirtin. - Bağlayıcı için arama yolları sağlamak için
-L
belirtin. - Hangi kitaplığın bağlanması gerektiğini sağlamak için
-l
belirtin.
Tüm alt projelerin hareketli olmasını istediğimiz için mutlak veya göreceli yollar kullanamayız. Örneğin şunu yapmayacağız: INCLUDEPATH += ../library/include ve elbette geçici bir derleme klasöründen kitaplık ikili dosyasına (.a dosyası) başvuramayız. “Endişelerin ayrılması” ilkesini takiben, uygulama proje dosyasının kütüphane detaylarından soyutlanacağını hemen anlayabiliriz. Bunun yerine, başlık dosyalarının vb. nerede bulunacağını söylemek kitaplığın sorumluluğundadır.
Bu sorunu çözmek için qmake'in include()
yönergesinden yararlanalım. Kitaplık projesinde, .pri
uzantılı yeni bir dosyaya başka bir qmake belirtimi ekleyeceğiz (uzantı herhangi bir şey olabilir, ancak burada i
içerme anlamına gelir). Bu nedenle, kitaplığın iki özelliği olacaktır: library.pro
ve library.pri
. Birincisi kütüphaneyi oluşturmak için, ikincisi ise tüketen bir projenin ihtiyaç duyduğu tüm detayları sağlamak için kullanılır.
library.pri dosyasının içeriği aşağıdaki gibi olacaktır:
LIBTARGET = library BASEDIR = $${PWD} INCLUDEPATH *= $${BASEDIR}/include LIBS += -L$${DESTDIR} -llibrary
BASEDIR
, kitaplık projesinin klasörünü belirtir (tam olarak, bizim durumumuzda library.pri
olan mevcut qmake belirtim dosyasının konumu). Tahmin edebileceğiniz gibi, INCLUDEPATH
/project/library/include
olarak değerlendirilecektir. DESTDIR
, derleme sisteminin (.o .a .so .dll veya .exe dosyaları) gibi çıktı yapılarını yerleştirdiği dizindir. Bu genellikle IDE'nizde yapılandırılır, bu nedenle çıktı dosyalarının nerede bulunduğuna dair hiçbir varsayımda bulunmamalısınız.
application.pro
dosyasına yalnızca include(../library/library.pri)
ekleyin ve işiniz bitti.
Bu durumda uygulama projesinin nasıl oluşturulduğunu gözden geçirelim:

- Topmost
project.pro
bir alt dizin projesidir. Önce kütüphane projesinin inşa edilmesi gerektiğini söylüyor. Böylece qmake, kitaplığın klasörüne girer ve onulibrary.pro
kullanarak oluşturur. Bu aşamadalibrary.a
üretilir veDESTDIR
klasörüne yerleştirilir. - Ardından qmake, uygulama alt klasörüne girer ve
application.pro
dosyasını ayrıştırır. qmake'e onu hemen okuması ve yorumlaması talimatını vereninclude(../library/library.pri)
yönergesini bulur. Bu,INCLUDEPATH
veLIBS
değişkenlerine yeni tanımlar ekler, böylece artık derleyici ve bağlayıcı, ekleme dosyalarını, kitaplık ikili dosyalarını ve hangi kitaplığın bağlanacağını nerede arayacağını bilir.
Kütüphane testleri projesinin oluşturulmasını atladık, ancak uygulama projesiyle aynı. Açıkçası, test projemizin test etmesi gereken kitaplığı da bağlaması gerekir.
Bu kurulumla, kitaplık projesini kolayca başka bir qmake projesine taşıyabilir ve onu dahil edebilir, böylece .pri
dosyasına referans verebilirsiniz. Üçüncü taraf kitaplıkları topluluk tarafından tam olarak bu şekilde dağıtılır.
config.pri
Karmaşık bir projede, birçok alt proje tarafından kullanılan bazı paylaşılan konfigürasyon parametrelerine sahip olmak çok yaygındır. Yinelemeyi önlemek için, include()
yönergesinden tekrar yararlanabilir ve üst düzey klasörde config.pri
oluşturabilirsiniz. Ayrıca, bu kılavuzda daha sonra tartışacağımıza benzer şekilde, alt projelerinizle paylaşılan ortak qmake “yardımcı programlarınız” olabilir.
Yapıları DESTDIR'a Kopyalama
Çoğu zaman, projelerin bir kitaplık veya uygulama ile birlikte dağıtılması gereken bazı "başka" dosyaları vardır. Oluşturma işlemi sırasında tüm bu dosyaları DESTDIR
kopyalayabilmemiz yeterlidir. Aşağıdaki parçacığı göz önünde bulundurun:
defineTest(copyToDestDir) { files = $$1 for(FILE, files) { DDIR = $$DESTDIR FILE = $$absolute_path($$FILE) # Replace slashes in paths with backslashes for Windows win32:FILE ~= s,/,\\,g win32:DDIR ~= s,/,\\,g QMAKE_POST_LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DDIR) $$escape_expand(\\n\\t) } export(QMAKE_POST_LINK) }
Not: Bu kalıbı kullanarak, dosyalar üzerinde çalışan kendi yeniden kullanılabilir işlevlerinizi tanımlayabilirsiniz.
Bu kodu /project/copyToDestDir.pri
içine yerleştirin, böylece aşağıdaki gibi zorlu alt projelere include()
:
include(../copyToDestDir.pri) MYFILES += \ parameters.conf \ testdata.db ## this is copying all files listed in MYFILES variable copyToDestDir($$MYFILES) ## this is copying a single file, a required DLL in this example copyToDestDir($${3RDPARTY}/openssl/bin/crypto.dll)
Not: DISTFILES aynı amaç için tanıtıldı, ancak yalnızca Unix'te çalışıyor.
Kod Oluşturma
Önceden oluşturulmuş bir adım olarak kod oluşturmanın harika bir örneği, bir C++ projesinin Google protobuf kullanmasıdır. Şimdi inşa sürecine protoc
yürütmeyi nasıl enjekte edebileceğimizi görelim.
Google'da kolayca uygun bir çözüm bulabilirsiniz, ancak önemli bir köşe vakasının farkında olmanız gerekir. A'nın B'ye atıfta bulunduğu iki sözleşmeniz olduğunu hayal edin.
A.proto <= B.proto
Önce A.proto
için kod üretecek olursak ( A.pb.h
ve A.pb.cxx
üretmek için) ve bunu derleyiciye beslersek, B.pb.h
bağımlılığı henüz mevcut olmadığından başarısız olur. Bunu çözmek için, ortaya çıkan kaynak kodunu oluşturmadan önce tüm proto kod oluşturma aşamasını geçmemiz gerekiyor.
Burada bu görev için harika bir pasaj buldum: https://github.com/jmesmon/qmake-protobuf-example/blob/master/protobuf.pri
Oldukça büyük bir komut dosyasıdır, ancak onu nasıl kullanacağınızı zaten bilmelisiniz:
PROTOS = A.proto B.proto include(protobuf.pri)
protobuf.pri
dosyasına bakarken, herhangi bir özel derlemeye veya kod oluşturmaya kolayca uygulanabilen genel kalıbı fark edebilirsiniz:
my_custom_compiler.name = my custom compiler name my_custom_compiler.input = input variable (list) my_custom_compiler.output = output file path + pattern my_custom_compiler.commands = custom compilation command my_custom_compiler.variable_out = output variable (list) QMAKE_EXTRA_COMPILERS += my_custom_compiler
Kapsamlar ve Koşullar
Genellikle, Windows veya MacOS gibi belirli bir platform için özel olarak bildirimler tanımlamamız gerekir. Qmake, önceden tanımlanmış üç platform göstergesi sunar: win32, macx ve unix. İşte sözdizimi:
win32 { # add Windows application icon, not applicable to unix/macx platform RC_ICONS += icon.ico }
Kapsamlar iç içe yerleştirilebilir, operatörleri kullanabilir !
, |
ve hatta joker karakterler:
macx:debug { # include only on Mac and only for debug build HEADERS += debugging.h } win32|macx { HEADERS += windows_or_macx.h } win32-msvc* { # same as win32-msvc|win32-mscv.net }
Not: Unix, Mac OS'de tanımlanmıştır! Mac OS için test etmek istiyorsanız (genel Unix değil), unix:!macx
koşulunu kullanın.
Qt Creator'da kapsam koşulları debug
ve release
beklendiği gibi çalışmıyor. Bunların düzgün çalışmasını sağlamak için aşağıdaki kalıbı kullanın:
CONFIG(debug, debug|release) { LIBS += ... } CONFIG(release, debug|release) { LIBS += ... }
Faydalı Fonksiyonlar
Qmake, daha fazla otomasyon ekleyen bir dizi gömülü işleve sahiptir.
İlk örnek, files()
işlevidir. Değişken sayıda kaynak dosya üreten bir kod oluşturma adımınız olduğunu varsayarsak. Hepsini SOURCES
şu şekilde dahil edebilirsiniz:
SOURCES += $$files(generated/*.c)
Bu, generated
alt klasördeki .c
uzantılı tüm dosyaları bulur ve bunları SOURCES
değişkenine ekler.
İkinci örnek öncekine benzer, ancak şimdi kod oluşturma, çıktı dosyası adlarını (dosya listesi) içeren bir metin dosyası üretti:
SOURCES += $$cat(generated/filelist, lines)
Bu sadece dosya içeriğini okuyacak ve her satırı SOURCES
için bir giriş olarak değerlendirecektir.
Not: Gömülü işlevlerin tam listesi burada bulunabilir: http://doc.qt.io/qt-5/qmake-function-reference.html
Uyarıları Hata Olarak Değerlendirme
Aşağıdaki kod parçası, daha önce açıklanan koşullu kapsam özelliğini kullanır:
*g++*: QMAKE_CXXFLAGS += -Werror *msvc*: QMAKE_CXXFLAGS += /WX
Bu karmaşıklığın nedeni, MSVC'nin bu seçeneği etkinleştirmek için farklı bir bayrağa sahip olmasıdır.
Git Sürümü Oluşturma
Aşağıdaki pasaj, Git'ten alınan mevcut SW sürümünü içeren bir önişlemci tanımı oluşturmanız gerektiğinde kullanışlıdır:
DEFINES += SW_VERSION=\\\"$$system(git describe --always --abbrev=0)\\\"
Bu, git
komutu mevcut olduğu sürece herhangi bir platformda çalışır. Git etiketlerini kullanırsanız, dal ilerlemiş olsa bile bu en son etikete göz atacaktır. Seçtiğiniz çıktıyı almak için git describe
komutunu değiştirin.
Çözüm
Qmake, platformlar arası Qt tabanlı projelerinizi oluşturmaya odaklanan harika bir araçtır. Bu kılavuzda, proje yapınızı esnek tutacak ve yapı belirtimlerinin okunması ve bakımının kolay olmasını sağlayacak temel araç kullanımını ve en sık kullanılan kalıpları inceledik.
Qt uygulamanızın nasıl daha iyi görüneceğini öğrenmek ister misiniz? Deneyin: Bezier Eğrileri ve QPainter Kullanarak C++'da Yuvarlak Köşe Şekilleri Nasıl Elde Edilir: Adım Adım Kılavuz