Download pdf - Undocumented Qmake

Transcript
  • 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


Recommended