I use the Qt library and qmake to build my bloodstain pattern analysis software. qmake is a great tool for cross-platform development because it lets you use one relatively succinct description [a .pro file] to generate Xcode projects, MSVC projects, and makefiles. On the Mac OS X side of things, I use one qmake .pro file to generate three xcode projects: release, beta, and demo. My directory structure looks like this:
Overall this works well, but there’s an issue with the Info.plist file.
I have something like this in Example.pro:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
CONFIG (beta) { MOC_DIR = moc/beta UI_DIR = UI/beta DEFINES += EXAMPLE_BETA OBJ_SUB_DIR = Beta win32:RC_FILE = resources/ExampleBeta.rc TARGET = ExampleBeta mac { QMAKE_INFO_PLIST = resources/Beta/Info.plist } } [... and similar sections for Demo and Release] |
The problem is that when qmake generates the Xcode project, it copies the Info.plist file specified using QMAKE_INFO_PLIST into the directory next to the Xcode project it’s generating.
This means that when I generate my three projects, it simply overwrites the other Info.plist files resulting the last one I generated being the active one. Then I have to copy over the correct one by hand every time I want to build a different project. Not ideal and prone to mistakes.
What I want to happen – and what I expected to happen when specifying QMAKE_INFO_PLIST in the .pro file – is for qmake to, well, use the one I specified for the project!
So how do we fix this? The only way I could figure out was to modify qmake itself. I found that someone had reported this issue – qmake: Using QMAKE_INFO_PLIST should modify the xcode project to reference it and not copy this file to Info.plist [QTBUG-2720], but it was closed and nobody had a solution, so I took a shot at it.
My solution does three things:
- Adds a warning if the file referenced in QMAKE_INFO_PLIST does not exist.
- Uses the name of the file in QMAKE_INFO_PLIST instead of always changing it to “Info.plist”.
- Adds PLIST_DIR which specifies where to put the copy of QMAKE_INFO_PLIST for building [copying is necessary because of substitution of @EXECUTABLE@ etc.]. This is analogous to RCC_DIR.
Here is the diff against Qt v4.7.3-2192-g1dd89b6, though I know it works against the 4.8 strain since I’m using that as well:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
index 24ae8ed..788dddd 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -1277,14 +1277,21 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) plist_in_text = plist_in_text.replace("@TYPEINFO@", (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4))); - QFile plist_out_file("Info.plist"); + QString plist_dir; + if (!project->isEmpty("PLIST_DIR")) + plist_dir = project->first("PLIST_DIR"); + QString plist_in_filename = QFileInfo(plist_in_file).fileName(); + QFile plist_out_file(plist_dir + plist_in_filename); if(plist_out_file.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream plist_out(&plist_out_file); plist_out << plist_in_text; - t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", "Info.plist") << ";" << "\n"; + t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", fixForOutput(plist_dir + plist_in_filename)) << } } } + else { + warn_msg(WarnLogic, "QMAKE_INFO_PLIST file not found %s", plist.toLatin1().constData()); + } } #if 1 t << "\t\t\t\t" << writeSettings("BUILD_ROOT", escapeFilePath(qmake_getpwd())) << ";" << "\n"; diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 80c31e3..f17076c 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -229,7 +229,7 @@ MakefileGenerator::initOutPaths() v["PRECOMPILED_DIR"] = v["OBJECTS_DIR"]; QString dirs[] = { QString("OBJECTS_DIR"), QString("DESTDIR"), QString("QMAKE_PKGCONFIG_DESTDIR"), QString("SUBLIBS_DIR"), QString("DLLDESTDIR"), QString("QMAKE_LIBTOOL_DESTDIR"), - QString("PRECOMPILED_DIR"), QString() }; + QString("PRECOMPILED_DIR"), QString("PLIST_DIR"), QString() }; for(int x = 0; !dirs[x].isEmpty(); x++) { if(v[dirs[x]].isEmpty()) continue; |
I’m certainly not an expert on the qmake code, so I have two questions for the more knowledgeable among you:
- In the output for INFOPLIST_FILE, I use the fixForOutput() function. Is this the correct function?
- I added PLIST_DIR in makefile.cpp so that the directory will be created. Is this the proper place to do this?
I hope someone else finds this useful!