Vous êtes sur la page 1sur 9

3/26/2015

UndocumentedQmake

Index Software

UndocumentedQmake
LastUpdate:20060829
InJuly2006,Ichangedjobs,andnolongeruseQtatwork.IintendtodabbleabitwithQt,butIwon'tbe
spendinganythinglikeasmuchtimewithitaspreviously.SoIdon'texpecttobeaddingmuchtothis
pagefromnowon.
Ifyou'reusingQt,thenthechancesareyouuseqmake.It'spossibletointegrateQtintoothermake
systems,butformostpeople,it'salotofhardworkforlittlegain.Personally,Ifindqmakequitegood,
butithasonebigproblem.Thedocumentationisincomplete.Inadditiontothedocumentationavailable
inassistant,I'vefounditinvaluabletosearchthroughtheqmakesourcecodetofindouthowthingsare
done,andalsotodiscoverundocumentedfeatures.Thiswebpageisintendedtodocumentsomeofthese
features.ThecurrentversionofQtatthetimeofwritingwasQt3.3.4.
MyexperienceofQt4isquitelimited.However,Idohavetheimpressionthatqmakehasbeen
substantiallyrewritten,andthatthedocumentationismoreexhaustive
TheotherthingthatI'vefoundinvaluableistostudytheqmake.conffilesin$QTDIR/mkspecs
attentively.Fromstudyingthesefiles,youcanseehowqmakedoesthingsbydefault,andyoucanadapt
themtoyouneedsifrequired.
I'vetestedmostofthesethingsonSolaris,LinuxandHPUX.Ijustaboutgotmostthingstowork,with
somedifficulty,onWindows2000usingcygwin.

Using$$ORIGIN
MostunicesallowyoutospecifytheRPATHforapplications.Thisispartofthepaththatwillbe
searchedfordynamiclibraries.Inaddition,youcanspecifyarelativepathwiththe$ORIGINvariable.
Thisisnotanenvironmentvariable,itispartoftheapplication'sRPATH.Forinstance,saythe
applicationisinstalledin/opt/foo/bin/fooappandtherearedynamiclibrariesin/opt/foo/lib.Youcould
specifytheabsolutepath(/opt/foo/lib)intheapplication.Oralternativelyyoucouldspecifytherelative
pathwith$ORIGIN/../lib.Enoughbackground.Howdoyouactuallydothis?OnSolariswithSun
Studio,itwouldbeachievedbyaddingR$ORIGIN/../libtothelinkcommand.(g++usesWl,rpath,
insteadofR).Theqmakevariableforthisis,naturally,QMAKE_RPATH.Sowhatistheproblem?
Well,themakefileneedstocontain'R$$ORIGIN/../lib'(twodollarssothatitdoesn'ttake$ORIGINfor
amakeMACRO).
IfyouareusingQt3.3.8(andIguess4.x,butIhaven'tchecked),thenyoucansimplyuse\$$ORIGIN.
ButifyouareusinganolderversionofQt(I'vecheckedthiswith3.1.1),thenyouhaveaproblem.
$$ORIGINlookslikeavariabletoqmake.I'vetriedallsortsofthingstoescapethedollars,
($$$$ORIGIN,\$\$ORIGIN,singlequotes,doublequotes...).Butalwayseitherthe$$ORIGINistreated
asavariableanddisappears,orelsetheescapingistooefficient,andtheescapecharactersendupinthe
generatedmakefile.OnesolutionistosetanORIGINenvironmentvariable:
exportORIGIN=\$\$ORIGIN
http://paulf.free.fr/undocumented_qmake.html

1/9

3/26/2015

UndocumentedQmake

andthenusethatintheprojectfile:
QMAKE_LFLAGS=L/bar/build/libR$$(ORIGIN)/../liblibrary=stlport4
Anotherpossibility,abitcleaner,istobeattheqmakevariablesattheirowngame:
DOLLAR=$
QMAKE_LFLAGS=L/bar/build/libR$${DOLLAR}$${DOLLAR}ORIGIN/../lib
library=stlport4
Thefirstcurlybracesaren'tstrictlynecessary.Justimagineexplainingthatbytelephonesupport,"minus
rdollardollardollardollardollardollar".Hmm!

QMAKE_EXTRA_WIN_TARGETS,QMAKE_EXTRA_WIN_COMPILERS
ThedocumentationcoversQMAKE_EXTRA_UNIX_TARGETSand
QMAKE_EXTRA_UNIX_COMPILERS,butnottheirWINcounterparts.Thesecertainlydoexistfor
Windowsaswell.

No.inheaderincludepath
Add"no_include_pwd"toCONFIGandI"."willnolongerbeaddedtoINCPATH.Youmightwantto
dothis,forinstance,ifyouhaveafilelikestring.hinyourproject,butyouwanttoincludethesystem
versionbydefault.

NoeliminationofduplicateentriesinLIBS
Add"no_smart_library_merge"toCONFIG.

Escaping'{'and'}'inaprojectfile
Fromqtinterestmailinglist
First,echo${0##*/}isthecorrectthingtouse.

GettingpathsforMSSDKandDDK
Fromqtinterestmailinglist
Ithinkthatthisisalsoonan'undocumentedQt'wiki.
#FindtheSDK
SYSTEM_CMD=$$quote(regquery
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MicrosoftSDK\Directories/v
"InstallDir")
SYSTEM_RET=$$system($${SYSTEM_CMD})
FORLOOP=8910111213141516
for(i,FORLOOP):SDKPATH+=$$member(SYSTEM_RET,$${i})
SDKPATH=$$quote($${SDKPATH})
http://paulf.free.fr/undocumented_qmake.html

2/9

3/26/2015

UndocumentedQmake

#FindthenewestDDKcontainingheaders/libsfor$${DDK_TARGET}
DDK_TARGET=w2k
SYSTEM_CMD=$$quote(regquery
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WINDDK)
SYSTEM_RET=$$system($${SYSTEM_CMD})
FORLOOP=12111098765
for(i,FORLOOP){
REG_CURENTRY=$$member(SYSTEM_RET,$${i})
count(REG_CURENTRY,1){
SYSTEM_CMD2=$$quote(regquery$${REG_CURENTRY}/v"LFNDirectory")
SYSTEM_RET2=$$system($${SYSTEM_CMD2})
FORLOOP2=789101112131415
CURDDKPATH=
for(j,FORLOOP2){
CURDDKPATH+=$$member(SYSTEM_RET2,$${j})
}
CURDDKPATH=$$quote($${CURDDKPATH})
exists($${CURDDKPATH}/inc/$${DDK_TARGET}):DDKPATH=
$$quote($${CURDDKPATH})
}
}

Settingsystemdependentoptions
Theexistingqmakesupportissufficientformostneeds,inparticular,thevalueoftheQMAKESPEC
environmentvariable.Thereare,however,afewcaseswherethismightnotbeenough,e.g.,ifyouneed
todistinguishbetweenLinuxonx86andPPC,orbetweenSolarisonSPARCandx86.Asanexample,
onUnixsystems(possiblyincludingWindowswithcygwin),thenyoucoulduse
SYSTEM=$$system(unamesp|sed's//_/g')
Analternative[Qt3.3andlater]istouseproperties.Foreachsystemthatyouuse,youwouldissuea
commandlike
qmakesetSYSTEMLinuxPPC
Youcouldthenuseinyourprojectfilesomethinglike
CONFIG+=$$[SYSTEM]
LinuxPPC{
message(LinuxonPPC)
}
Theoneslightdrawbackofthisapproachisthatitrequireseachusertoperformthe'qmakeset'stepto
correctlyconfiguretheirenvironment.Usuallythiswouldfallslightlyoutofthescopeofasource
managementsystem.Thusyouwouldnotbeabletodosomethinglike"checkout&make".Ifyoudo
takethissortofapproach,thenyoucanprotectyourselfagainsterrorslikethepropertynotbeingsetlike
this:
isEmpty($$[FOO]){
http://paulf.free.fr/undocumented_qmake.html

3/9

3/26/2015

UndocumentedQmake

error(YoumustrunqmakesetFOOwhateverbeforerunningqmake)
}

AddingtoINCPATHafter$QTDIR/include
Inyour.profile,add
QMAKE_INCDIR_QT+=my/path

NotlinkingwiththeoutputofQMAKE_EXTRA_UNIX_COMPILERS
qmakeassumesthattheoutputoftheextracompilersisdestinedtobelinkedintothefinallibraryor
application.Ifthisisn'tthecase,thenyouneedtodosomethingtostopit.
If"mycompiler"isthenameofyourcompilercompoundvariable,thenifyouhaveamember.CONFIG
settono_link,thentheoutputwon'tgetlinked.Example.
mycompiler.output=${QMAKE_FILE_BASE}.out
mycompiler.input=MYCOMPILER_INPUT_FILES
mycompiler.commands=foo${QMAKE_FILE_NAME}
mycompiler.CONFIG=no_link
QMAKE_EXTRA_UNIX_COMPILERS+=my_compiler
Exampleswhenyoumightwanttodothisareforthingslikegeneratingdocumentation.

Usingflexandbison
qmakehasbuiltinsupportforlexandyacc.Unfortunately,itwon'tworkwithflexandbison.

lex
lexisquiteeasy,justset
QMAKE_LEX=flex

bison
bisonisanotherstory.Withabitofeffort,though,itcanbecoerced.Thefirststepiseasy,likelex.
QMAKE_YACC=bison
Afterthat,we'reintrouble.yaccgeneratesfiles"y.tab.h"and"y.tab.c".Qmakeaddstothemakefilerule
acommandthatmovesthesefilesto"<myfile>_yacc.h"and"<myfile>_yacc.c".
bisongenerates"<myfile>.Y.tab.c"and"<myfile>.Y.tab.h"sothemovestagefails,andalsoevidentlyso
doesthecompile.
SoIusedQMAKE_YACCFLAGS_MANGLE,whicharen'tdocumented.Ithinkthatitissupposedto
allowyoutochangethewaythatvariablesarenames(defaultprefixis"yy_",defaultqmakeprefixis"
<myfile>".I'vekeptthisprefix,butforcedbisontogenerate"y.tab.h"and"y.tab.c",whichiswhatqmake
http://paulf.free.fr/undocumented_qmake.html

4/9

3/26/2015

UndocumentedQmake

needsforthesubsequentrenameandthencompile.Phew!
MysolutiononSolarisdidn'tworkonLinux.Thistime,Iusedthesamebisonoptiontocontrolthe
outputfilename,butIalsoneededdtogeneratetheheaderfile.Ialsohadtoclear
QMAKE_YACC_HEADER/QMAKE_YACC_SOURCE.
OnSolaris
Usingthesfwversionofbison,1.35
solariscc{
QMAKE_YACCFLAGS_MANGLE=oy.tab.cp$base
}
OnLinux
linuxg++{
QMAKE_YACCFLAGS=doy.tab.c
QMAKE_YACC_HEADER=
QMAKE_YACC_SOURCE=
}

Addingadoxygentarget
Fromqtinterestmailinglist
Youcanatleastmake"customtargets",suchasfor'makestrip'.Seedocsaboutqmake.Notsurehowto
runthemautomaticallyafterlinkingthough.
Example(forrunningdoxygenoverthesourceswith'makedoc'):
#customtarget'doc'in*.profile
dox.target=doc
dox.commands=doxygenDoxyfile\
testddoxydoc/html/images||mkdirdoxydoc/html/images\
cpdocumentation/images/*doxydoc/html/images
dox.depends=
...
#somewhereelseinthe*.profile
QMAKE_EXTRA_UNIX_TARGETS+=dox

Strippingexecutables
Fromqtinterestmailinglist
Youcanusesomethinglikethisinthe.profile(untested):
unix:QMAKE_POST_LINK=strip$(TARGET)
!unix:QMAKE_POST_LINK=xxx$(TARGET)
http://paulf.free.fr/undocumented_qmake.html

5/9

3/26/2015

UndocumentedQmake

ReplacexxxwiththesamelinebutwithwhateverthestripcommandiscalledonWindows.

Buildinginsubdirectories
Perhapsthesimplestissomethinglike
system(cdcontrib/sshaskpass&&$${MAKECMD})
WhereyouwouldhavepreviouslysettheappropriateMAKECMD.

Preinstallheaders
Ihadalengthybattleatmyplaceofworkgettingsomethinglike"makeinstall_headers"towork(oreven
better,tobedoneasaprerequisitebeforeanyothertargets,sojusttypingmakewillpreinstallany
exportedheaders).Why?Well,wehavealotofsourcethatincludesheadersinthecommonunixwayas
#include<library/header.h>,inparticularwhentheheadersaregoingtobeexported.Thisposesno
problemforalibrarythathasallsuchheadersinadirectory"basedir/include/library",youcanjustadd
INCLUDEPATH+=include,andallwillbewell.
Whenthefilesaren'torganizedinthisway,therearethreepossibilities.
1. Editthefiles.Notanoptionforme.
2. Changethedirectorystructure(orfakeitwithlinks).Thiswouldworkinmostcases,butIhavea
fewlibrariesthatdon'tconformtothepatternofonesourcedirectoryforone#includedirectory.
3. Fightitoutwithqmake.
Asyoumayhavegathered,it'snumberthreethatI'mgoingtopursuehere.I'vehadthreegoesatsolving
thisproblem,allwithvaryingdegreesofsuccess.Sadlynoneofthemseemstobe100%reliableonall
platforms.Iusuallyfindthatsolutions2and3takeafewiterationsofqmakeandmakebeforeeverything
settlesdown(i.e.,theintermediatemocanduigeneratedfileshavebeengenerated).

1.UsetheINSTALLSqmakevariable
Thissoundslikeitfitsthebill,butunfortunately,thereareacoupleofgotchas,whichI'llcometoshortly.
Here'showitworks.Youdefineacompoundvariable(Iusuallycallit"headers".Ifyouneedmorethan
onedestination,you'llneedmorethanonecompoundvariable.Withinyourvariable,youdefinethepath
(wherethefileswillgo)andthefiles(whichfilestocopy).
Example.Thisassumesthatyou'vealreadydefinedINSTALLBASE,TARGET,VERSIONand
HEADERS.
headers.path=$$INSTALLBASE/include/$${TARGET}_$${VERSION}/$${TARGET}
headers.files=$$HEADERS
INSTALLS+=headers
PRE_TARGETDEPS+=install_headers
Nowforthegotchas.Firstofall,bydefaultqmakewillgenerateamakefilethatusesthebasicOScopy
functiontoinstallthefiles(e.g.,cponUnixandcopyonWindowsdon'tknowforMac).Thiswillcause
thedestinationfiletohaveitstimestampsettothetimethatitwascopied.Obviously,thisisacalamity
http://paulf.free.fr/undocumented_qmake.html

6/9

3/26/2015

UndocumentedQmake

foraninterdependentsetoflibrariesbuiltwithmake.Theupdatedtimestampswillcausealotof
unnecessarycompiles.Thereisasolution.QMAKE_COPYtotherescue!Simplysetthistosomething
like"cpfp"andallwillbewell.
OnWindows,Ihadabitofahardertime,andIendedupcreatingalittleshellscripttoovercomethefact
thatthoughIwasrunningnmakewithincygwin,withinnmake,pathsallusebackslashes,whichcygwin
copydoesn'tunderstand.Thescriptbasicallydoes
cpfp`cygpathu"$@"`
Nowforthesecondgotcha.Thisonehasnorealsolution.Myaimwastohave
HEADERS=...
INSTALLS=...asabove...
PRE_TARGETDEPS+=install_headers
AlliswelluntilyouwanttoaddanyuicormocgeneratedheaderstoINSTALLS.Theneverythinggoes
pearshaped.There'snoproblemputtingthegeneratedheadersbeforeinstall_headersin
PRE_TARGETDEPS.Thereisaproblemwithacirculardependencythough.qmakeadds'all'tothe
dependenciesforINSTALLS,buttheuic/mocgeneratedheadersdependonthe.ui/.hfiles.Some
versionsofmakewilljustcomplain,otherswillterminatewhentheyseeacirculardependency.
Ithinkthatthebestsolutionwouldbetofixqmaketoallowustoturnoffthedependencyon'all'.For
example
headers.path=$$INSTALLBASE/include/$${TARGET}_$${VERSION}/$${TARGET}
headers.files=$$HEADERS
headers.CONFIG+=no_all
INSTALLS+=headers
PRE_TARGETDEPS+=install_headers
Note:youmaywanttohavedifferentvariablesforexportedandprivateheaders,e.g.,
PRIVATE_HEADERS=...
EXPORTED_HEADERS=...
HEADERS=$$PRIVATE_HEADERS$$EXPORTED_HEADERS
...
headers.files=$$EXPORTED_HEADERS
We'llhavetowaitandseeifTrolltechtakeitup(oranyoneelseforthatmatter).
Becauseofthisproblem,IgaveupwiththissolutionwhereverIneedtoinstallgeneratedheaders.
But,holdthepresses!

1.aUseINSTALLSandpatchqmake
Itookupmyownchallengeandmadeasmall(andasitturnsout,quitesimple)modtoqmake
($QTDIR/qmake/generators/makefile.cp).Hereisthepatch.BeforeImadethispatch,Iwasusing
INSTALLSforprojectswhereuigeneratedheaderswerenotrequiredtobepublic.Iwasusingthe
methodoutlinedinpoint2belowforthoselibrarieswhereIneededtoexportgeneratedheaders.NowI
http://paulf.free.fr/undocumented_qmake.html

7/9

3/26/2015

UndocumentedQmake

useINSTALLSforeverything.

2.UseQMAKE_EXTRA_UNIX_TARGETS
BasicallytheideaistoreinventtheINSTALLSmechanism,butwithoutthecirculardependencies.I
wrotealittleTclscriptthattakesthedestinationpath,thenameofa.profiletogenerateandalistof
headers.Inmy.profileIput
HEADERS_PATH=$$INSTALLBASE/include/$${TARGET}_$${VERSION}/$${TARGET}
system(preinstallheaders.tcl$$HEADERS_PATHpih.pro$$HEADERS)
include(pih.pro)
Andthiswouldgenerate"pih.pro"containing
mkdir.commands=$$QMAKE_MKDIR[pathtoinstallto]
mkdir.target=[pathtoinstallto]
iheader0.target=[pathtoinstallto]/header.h
iheader0.commands=$$QMAKE_COPYsrc/header.h[pathtoinstallto]
iheader0.depends=src/header.h
...
iheaderX...
unix:QMAKE_EXTRA_UNIX_TARGETS+=mkdiriheader0...iheaderX
PRE_TARGETDEPS+=[pathtoinstallto][pathtoinstallto]/header.h
...
Notverypretty,butitgotthejobdone.Iputthe"pih.pro"fileintheworkingdirectorywherethere
wouldbesomeriskofoverwritingifIbuiltontwoplatformssimultaneously.Onesolutiontothiswould
betoputthefileinaplatformspecificdirectory.Ontopofthat,whentheprojectfileincludespih.pro,
themakefilewillcontainadependencybetweenpih.proanditself.Thismeansthatifyougoandbuildon
adifferentplatform,makewillcauseqmaketoregeneratethemakefile(andpih.pro),whichis
unnecessary.
AnotherthingthatIneverbotheredtosolvewasifthefilesneedtobeinstalledtomorethanone
directory,ifImadetwocallstopreinstallheaders.tcl,theywouldbothcreateextratargetsstartingwith
iheader0,sothesecondonewouldhidethethird.Thisshouldbeeasyenoughtosolve,butasitonly
affectedonelibraryforme,itwasn'tworththeeffort.
Allthesame,Ithoughttomyselfthattheremustbesomethingprettier.So...

3.UseQMAKE_EXTRA_UNIX_COMPILERS
It'sprehapsnotthemostobviousthingtodo,usea'compiler'to'install'aheader.Butthereyougo.
Here'sanexample.
install_headers.output=[pathtoinstallto]/${QMAKE_FILE_BASE}.h
install_headers.input=INSTALL_HEADERS
install_headers.commands=$$QMAKE_COPY${QMAKE_FILE_NAME}
$$make_dir.target
install_headers.CONFIG=no_link
QMAKE_EXTRA_UNIX_TARGETS+=make_dir
http://paulf.free.fr/undocumented_qmake.html

8/9

3/26/2015

UndocumentedQmake

QMAKE_EXTRA_UNIX_COMPILERS+=install_headers
INSTALL_HEADERS=$$HEADERS$$GENERATED_HEADERS
PRE_TARGETDEPS+=$$make_dir.target$$UIDIR$$GENERATED_HEADERS
$$INST_HDRS$$INST_GEN_HDRS
Afewcommentsareinorder.Firstly,'make_dir'isthesamethingasinpoint2above.It'stheretoensure
thatthedestinationdirectoryexistsbeforeanyattemptatinstallingfiles.There'snoneedfora.depends
field.Iuse${QMAKE_FILE_BASE}.hfortheoutputsince${QMAKE_FILE_NAME}mayincludean
undesirablerelativepath.make_dirisatarget,justlikemkdirinthepih.profileinpart2above.$$UIDIR
needstobeinthePRE_TARGETDEPSbefore$$GENERATED_HEADERS,sincethatiswherethey
getput.$$GENERATED_HEADERSneedstobebefore$$INST_GEN_HDRSsincetheheadersneed
tobegeneratedbeforetheycanbeinstalled!
CopyrightPaulJohnFloyd20052007,2009

http://paulf.free.fr/undocumented_qmake.html

9/9

Vous aimerez peut-être aussi