undocumented qmake
DESCRIPTION
ryjhtyjutTRANSCRIPT
-
3/26/2015 UndocumentedQmake
http://paulf.free.fr/undocumented_qmake.html 1/9
Index Software
UndocumentedQmakeLastUpdate:20060829
InJuly2006,Ichangedjobs,andnolongeruseQtatwork.IintendtodabbleabitwithQt,butIwon'tbespendinganythinglikeasmuchtimewithitaspreviously.SoIdon'texpecttobeaddingmuchtothispagefromnowon.
Ifyou'reusingQt,thenthechancesareyouuseqmake.It'spossibletointegrateQtintoothermakesystems,butformostpeople,it'salotofhardworkforlittlegain.Personally,Ifindqmakequitegood,butithasonebigproblem.Thedocumentationisincomplete.Inadditiontothedocumentationavailableinassistant,I'vefounditinvaluabletosearchthroughtheqmakesourcecodetofindouthowthingsaredone,andalsotodiscoverundocumentedfeatures.Thiswebpageisintendedtodocumentsomeofthesefeatures.ThecurrentversionofQtatthetimeofwritingwasQt3.3.4.
MyexperienceofQt4isquitelimited.However,Idohavetheimpressionthatqmakehasbeensubstantiallyrewritten,andthatthedocumentationismoreexhaustive
TheotherthingthatI'vefoundinvaluableistostudytheqmake.conffilesin$QTDIR/mkspecsattentively.Fromstudyingthesefiles,youcanseehowqmakedoesthingsbydefault,andyoucanadaptthemtoyouneedsifrequired.
I'vetestedmostofthesethingsonSolaris,LinuxandHPUX.Ijustaboutgotmostthingstowork,withsomedifficulty,onWindows2000usingcygwin.
Using$$ORIGIN
MostunicesallowyoutospecifytheRPATHforapplications.Thisispartofthepaththatwillbesearchedfordynamiclibraries.Inaddition,youcanspecifyarelativepathwiththe$ORIGINvariable.Thisisnotanenvironmentvariable,itispartoftheapplication'sRPATH.Forinstance,saytheapplicationisinstalledin/opt/foo/bin/fooappandtherearedynamiclibrariesin/opt/foo/lib.Youcouldspecifytheabsolutepath(/opt/foo/lib)intheapplication.Oralternativelyyoucouldspecifytherelativepathwith$ORIGIN/../lib.Enoughbackground.Howdoyouactuallydothis?OnSolariswithSunStudio,itwouldbeachievedbyaddingR$ORIGIN/../libtothelinkcommand.(g++usesWl,rpath,insteadofR).Theqmakevariableforthisis,naturally,QMAKE_RPATH.Sowhatistheproblem?Well,themakefileneedstocontain'R$$ORIGIN/../lib'(twodollarssothatitdoesn'ttake$ORIGINforamakeMACRO).
IfyouareusingQt3.3.8(andIguess4.x,butIhaven'tchecked),thenyoucansimplyuse\$$ORIGIN.ButifyouareusinganolderversionofQt(I'vecheckedthiswith3.1.1),thenyouhaveaproblem.$$ORIGINlookslikeavariabletoqmake.I'vetriedallsortsofthingstoescapethedollars,($$$$ORIGIN,\$\$ORIGIN,singlequotes,doublequotes...).Butalwayseitherthe$$ORIGINistreatedasavariableanddisappears,orelsetheescapingistooefficient,andtheescapecharactersendupinthegeneratedmakefile.OnesolutionistosetanORIGINenvironmentvariable:
exportORIGIN=\$\$ORIGIN
http://paulf.free.fr/index.htmlhttp://paulf.free.fr/software.html
-
3/26/2015 UndocumentedQmake
http://paulf.free.fr/undocumented_qmake.html 2/9
andthenusethatintheprojectfile:
QMAKE_LFLAGS=L/bar/build/libR$$(ORIGIN)/../liblibrary=stlport4
Anotherpossibility,abitcleaner,istobeattheqmakevariablesattheirowngame:
DOLLAR=$QMAKE_LFLAGS=L/bar/build/libR$${DOLLAR}$${DOLLAR}ORIGIN/../liblibrary=stlport4
Thefirstcurlybracesaren'tstrictlynecessary.Justimagineexplainingthatbytelephonesupport,"minusrdollardollardollardollardollardollar".Hmm!
QMAKE_EXTRA_WIN_TARGETS,QMAKE_EXTRA_WIN_COMPILERS
ThedocumentationcoversQMAKE_EXTRA_UNIX_TARGETSandQMAKE_EXTRA_UNIX_COMPILERS,butnottheirWINcounterparts.ThesecertainlydoexistforWindowsaswell.
No.inheaderincludepath
Add"no_include_pwd"toCONFIGandI"."willnolongerbeaddedtoINCPATH.Youmightwanttodothis,forinstance,ifyouhaveafilelikestring.hinyourproject,butyouwanttoincludethesystemversionbydefault.
NoeliminationofduplicateentriesinLIBS
Add"no_smart_library_merge"toCONFIG.
Escaping'{'and'}'inaprojectfile
Fromqtinterestmailinglist
First,echo${0##*/}isthecorrectthingtouse.
GettingpathsforMSSDKandDDK
Fromqtinterestmailinglist
Ithinkthatthisisalsoonan'undocumentedQt'wiki.
#FindtheSDKSYSTEM_CMD=$$quote(regqueryHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MicrosoftSDK\Directories/v"InstallDir")SYSTEM_RET=$$system($${SYSTEM_CMD})FORLOOP=8910111213141516for(i,FORLOOP):SDKPATH+=$$member(SYSTEM_RET,$${i})SDKPATH=$$quote($${SDKPATH})
-
3/26/2015 UndocumentedQmake
http://paulf.free.fr/undocumented_qmake.html 3/9
#FindthenewestDDKcontainingheaders/libsfor$${DDK_TARGET}DDK_TARGET=w2kSYSTEM_CMD=$$quote(regqueryHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WINDDK)SYSTEM_RET=$$system($${SYSTEM_CMD})FORLOOP=12111098765for(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=789101112131415CURDDKPATH=for(j,FORLOOP2){CURDDKPATH+=$$member(SYSTEM_RET2,$${j})}CURDDKPATH=$$quote($${CURDDKPATH})exists($${CURDDKPATH}/inc/$${DDK_TARGET}):DDKPATH=$$quote($${CURDDKPATH})}}
Settingsystemdependentoptions
Theexistingqmakesupportissufficientformostneeds,inparticular,thevalueoftheQMAKESPECenvironmentvariable.Thereare,however,afewcaseswherethismightnotbeenough,e.g.,ifyouneedtodistinguishbetweenLinuxonx86andPPC,orbetweenSolarisonSPARCandx86.Asanexample,onUnixsystems(possiblyincludingWindowswithcygwin),thenyoucoulduse
SYSTEM=$$system(unamesp|sed's//_/g')
Analternative[Qt3.3andlater]istouseproperties.Foreachsystemthatyouuse,youwouldissueacommandlike
qmakesetSYSTEMLinuxPPC
Youcouldthenuseinyourprojectfilesomethinglike
CONFIG+=$$[SYSTEM]
LinuxPPC{message(LinuxonPPC)}
Theoneslightdrawbackofthisapproachisthatitrequireseachusertoperformthe'qmakeset'steptocorrectlyconfiguretheirenvironment.Usuallythiswouldfallslightlyoutofthescopeofasourcemanagementsystem.Thusyouwouldnotbeabletodosomethinglike"checkout&make".Ifyoudotakethissortofapproach,thenyoucanprotectyourselfagainsterrorslikethepropertynotbeingsetlikethis:
isEmpty($$[FOO]){
-
3/26/2015 UndocumentedQmake
http://paulf.free.fr/undocumented_qmake.html 4/9
error(YoumustrunqmakesetFOOwhateverbeforerunningqmake)}
AddingtoINCPATHafter$QTDIR/include
Inyour.profile,add
QMAKE_INCDIR_QT+=my/path
NotlinkingwiththeoutputofQMAKE_EXTRA_UNIX_COMPILERS
qmakeassumesthattheoutputoftheextracompilersisdestinedtobelinkedintothefinallibraryorapplication.Ifthisisn'tthecase,thenyouneedtodosomethingtostopit.
If"mycompiler"isthenameofyourcompilercompoundvariable,thenifyouhaveamember.CONFIGsettono_link,thentheoutputwon'tgetlinked.Example.
mycompiler.output=${QMAKE_FILE_BASE}.outmycompiler.input=MYCOMPILER_INPUT_FILESmycompiler.commands=foo${QMAKE_FILE_NAME}mycompiler.CONFIG=no_linkQMAKE_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".Qmakeaddstothemakefileruleacommandthatmovesthesefilesto"_yacc.h"and"_yacc.c".
bisongenerates".Y.tab.c"and".Y.tab.h"sothemovestagefails,andalsoevidentlysodoesthecompile.
SoIusedQMAKE_YACCFLAGS_MANGLE,whicharen'tdocumented.Ithinkthatitissupposedtoallowyoutochangethewaythatvariablesarenames(defaultprefixis"yy_",defaultqmakeprefixis"".I'vekeptthisprefix,butforcedbisontogenerate"y.tab.h"and"y.tab.c",whichiswhatqmake
-
3/26/2015 UndocumentedQmake
http://paulf.free.fr/undocumented_qmake.html 5/9
needsforthesubsequentrenameandthencompile.Phew!
MysolutiononSolarisdidn'tworkonLinux.Thistime,Iusedthesamebisonoptiontocontroltheoutputfilename,butIalsoneededdtogeneratetheheaderfile.IalsohadtoclearQMAKE_YACC_HEADER/QMAKE_YACC_SOURCE.
OnSolaris
Usingthesfwversionofbison,1.35
solariscc{QMAKE_YACCFLAGS_MANGLE=oy.tab.cp$base}
OnLinux
linuxg++{QMAKE_YACCFLAGS=doy.tab.cQMAKE_YACC_HEADER=QMAKE_YACC_SOURCE=}
Addingadoxygentarget
Fromqtinterestmailinglist
Youcanatleastmake"customtargets",suchasfor'makestrip'.Seedocsaboutqmake.Notsurehowtorunthemautomaticallyafterlinkingthough.Example(forrunningdoxygenoverthesourceswith'makedoc'):
#customtarget'doc'in*.profiledox.target=docdox.commands=doxygenDoxyfile\testddoxydoc/html/images||mkdirdoxydoc/html/images\cpdocumentation/images/*doxydoc/html/imagesdox.depends=
...#somewhereelseinthe*.profileQMAKE_EXTRA_UNIX_TARGETS+=dox
Strippingexecutables
Fromqtinterestmailinglist
Youcanusesomethinglikethisinthe.profile(untested):
unix:QMAKE_POST_LINK=strip$(TARGET)!unix:QMAKE_POST_LINK=xxx$(TARGET)
-
3/26/2015 UndocumentedQmake
http://paulf.free.fr/undocumented_qmake.html 6/9
ReplacexxxwiththesamelinebutwithwhateverthestripcommandiscalledonWindows.
Buildinginsubdirectories
Perhapsthesimplestissomethinglike
system(cdcontrib/sshaskpass&&$${MAKECMD})
WhereyouwouldhavepreviouslysettheappropriateMAKECMD.
Preinstallheaders
Ihadalengthybattleatmyplaceofworkgettingsomethinglike"makeinstall_headers"towork(orevenbetter,tobedoneasaprerequisitebeforeanyothertargets,sojusttypingmakewillpreinstallanyexportedheaders).Why?Well,wehavealotofsourcethatincludesheadersinthecommonunixwayas#include,inparticularwhentheheadersaregoingtobeexported.Thisposesnoproblemforalibrarythathasallsuchheadersinadirectory"basedir/include/library",youcanjustaddINCLUDEPATH+=include,andallwillbewell.
Whenthefilesaren'torganizedinthisway,therearethreepossibilities.
1. Editthefiles.Notanoptionforme.2. Changethedirectorystructure(orfakeitwithlinks).Thiswouldworkinmostcases,butIhavea
fewlibrariesthatdon'tconformtothepatternofonesourcedirectoryforone#includedirectory.3. Fightitoutwithqmake.
Asyoumayhavegathered,it'snumberthreethatI'mgoingtopursuehere.I'vehadthreegoesatsolvingthisproblem,allwithvaryingdegreesofsuccess.Sadlynoneofthemseemstobe100%reliableonallplatforms.Iusuallyfindthatsolutions2and3takeafewiterationsofqmakeandmakebeforeeverythingsettlesdown(i.e.,theintermediatemocanduigeneratedfileshavebeengenerated).
1.UsetheINSTALLSqmakevariable
Thissoundslikeitfitsthebill,butunfortunately,thereareacoupleofgotchas,whichI'llcometoshortly.
Here'showitworks.Youdefineacompoundvariable(Iusuallycallit"headers".Ifyouneedmorethanonedestination,you'llneedmorethanonecompoundvariable.Withinyourvariable,youdefinethepath(wherethefileswillgo)andthefiles(whichfilestocopy).
Example.Thisassumesthatyou'vealreadydefinedINSTALLBASE,TARGET,VERSIONandHEADERS.
headers.path=$$INSTALLBASE/include/$${TARGET}_$${VERSION}/$${TARGET}headers.files=$$HEADERSINSTALLS+=headersPRE_TARGETDEPS+=install_headers
Nowforthegotchas.Firstofall,bydefaultqmakewillgenerateamakefilethatusesthebasicOScopyfunctiontoinstallthefiles(e.g.,cponUnixandcopyonWindowsdon'tknowforMac).Thiswillcausethedestinationfiletohaveitstimestampsettothetimethatitwascopied.Obviously,thisisacalamity
-
3/26/2015 UndocumentedQmake
http://paulf.free.fr/undocumented_qmake.html 7/9
foraninterdependentsetoflibrariesbuiltwithmake.Theupdatedtimestampswillcausealotofunnecessarycompiles.Thereisasolution.QMAKE_COPYtotherescue!Simplysetthistosomethinglike"cpfp"andallwillbewell.
OnWindows,Ihadabitofahardertime,andIendedupcreatingalittleshellscripttoovercomethefactthatthoughIwasrunningnmakewithincygwin,withinnmake,pathsallusebackslashes,whichcygwincopydoesn'tunderstand.Thescriptbasicallydoes
cpfp`cygpathu"$@"`
Nowforthesecondgotcha.Thisonehasnorealsolution.Myaimwastohave
HEADERS=...INSTALLS=...asabove...PRE_TARGETDEPS+=install_headers
AlliswelluntilyouwanttoaddanyuicormocgeneratedheaderstoINSTALLS.Theneverythinggoespearshaped.There'snoproblemputtingthegeneratedheadersbeforeinstall_headersinPRE_TARGETDEPS.Thereisaproblemwithacirculardependencythough.qmakeadds'all'tothedependenciesforINSTALLS,buttheuic/mocgeneratedheadersdependonthe.ui/.hfiles.Someversionsofmakewilljustcomplain,otherswillterminatewhentheyseeacirculardependency.
Ithinkthatthebestsolutionwouldbetofixqmaketoallowustoturnoffthedependencyon'all'.Forexample
headers.path=$$INSTALLBASE/include/$${TARGET}_$${VERSION}/$${TARGET}headers.files=$$HEADERSheaders.CONFIG+=no_allINSTALLS+=headersPRE_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,IwasusingINSTALLSforprojectswhereuigeneratedheaderswerenotrequiredtobepublic.Iwasusingthemethodoutlinedinpoint2belowforthoselibrarieswhereIneededtoexportgeneratedheaders.NowI
http://paulf.free.fr/makefile.cpp.diff
-
3/26/2015 UndocumentedQmake
http://paulf.free.fr/undocumented_qmake.html 8/9
useINSTALLSforeverything.
2.UseQMAKE_EXTRA_UNIX_TARGETS
BasicallytheideaistoreinventtheINSTALLSmechanism,butwithoutthecirculardependencies.IwrotealittleTclscriptthattakesthedestinationpath,thenameofa.profiletogenerateandalistofheaders.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.hiheader0.commands=$$QMAKE_COPYsrc/header.h[pathtoinstallto]iheader0.depends=src/header.h...iheaderX...unix:QMAKE_EXTRA_UNIX_TARGETS+=mkdiriheader0...iheaderXPRE_TARGETDEPS+=[pathtoinstallto][pathtoinstallto]/header.h...
Notverypretty,butitgotthejobdone.Iputthe"pih.pro"fileintheworkingdirectorywheretherewouldbesomeriskofoverwritingifIbuiltontwoplatformssimultaneously.Onesolutiontothiswouldbetoputthefileinaplatformspecificdirectory.Ontopofthat,whentheprojectfileincludespih.pro,themakefilewillcontainadependencybetweenpih.proanditself.Thismeansthatifyougoandbuildonadifferentplatform,makewillcauseqmaketoregeneratethemakefile(andpih.pro),whichisunnecessary.
AnotherthingthatIneverbotheredtosolvewasifthefilesneedtobeinstalledtomorethanonedirectory,ifImadetwocallstopreinstallheaders.tcl,theywouldbothcreateextratargetsstartingwithiheader0,sothesecondonewouldhidethethird.Thisshouldbeeasyenoughtosolve,butasitonlyaffectedonelibraryforme,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}.hinstall_headers.input=INSTALL_HEADERSinstall_headers.commands=$$QMAKE_COPY${QMAKE_FILE_NAME}$$make_dir.targetinstall_headers.CONFIG=no_link
QMAKE_EXTRA_UNIX_TARGETS+=make_dir
-
3/26/2015 UndocumentedQmake
http://paulf.free.fr/undocumented_qmake.html 9/9
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'stheretoensurethatthedestinationdirectoryexistsbeforeanyattemptatinstallingfiles.There'snoneedfora.dependsfield.Iuse${QMAKE_FILE_BASE}.hfortheoutputsince${QMAKE_FILE_NAME}mayincludeanundesirablerelativepath.make_dirisatarget,justlikemkdirinthepih.profileinpart2above.$$UIDIRneedstobeinthePRE_TARGETDEPSbefore$$GENERATED_HEADERS,sincethatiswheretheygetput.$$GENERATED_HEADERSneedstobebefore$$INST_GEN_HDRSsincetheheadersneedtobegeneratedbeforetheycanbeinstalled!
CopyrightPaulJohnFloyd20052007,2009
http://validator.w3.org/check/referer