summaryrefslogtreecommitdiffstats
path: root/qmake
diff options
context:
space:
mode:
Diffstat (limited to 'qmake')
-rw-r--r--qmake/CHANGES99
-rw-r--r--qmake/Makefile.unix349
-rw-r--r--qmake/Makefile.win32218
-rw-r--r--qmake/Makefile.win32-g++360
-rw-r--r--qmake/Makefile.win32-g++-sh359
-rw-r--r--qmake/cachekeys.h132
-rw-r--r--qmake/generators/integrity/gbuild.cpp442
-rw-r--r--qmake/generators/integrity/gbuild.h74
-rw-r--r--qmake/generators/mac/pbuilder_pbx.cpp1861
-rw-r--r--qmake/generators/mac/pbuilder_pbx.h88
-rw-r--r--qmake/generators/makefile.cpp3297
-rw-r--r--qmake/generators/makefile.h309
-rw-r--r--qmake/generators/makefiledeps.cpp961
-rw-r--r--qmake/generators/makefiledeps.h132
-rw-r--r--qmake/generators/metamakefile.cpp572
-rw-r--r--qmake/generators/metamakefile.h82
-rw-r--r--qmake/generators/projectgenerator.cpp511
-rw-r--r--qmake/generators/projectgenerator.h71
-rw-r--r--qmake/generators/symbian/initprojectdeploy_symbian.cpp379
-rw-r--r--qmake/generators/symbian/initprojectdeploy_symbian.h82
-rw-r--r--qmake/generators/symbian/symbian_makefile.h105
-rw-r--r--qmake/generators/symbian/symbiancommon.cpp1117
-rw-r--r--qmake/generators/symbian/symbiancommon.h133
-rw-r--r--qmake/generators/symbian/symmake.cpp1136
-rw-r--r--qmake/generators/symbian/symmake.h149
-rw-r--r--qmake/generators/symbian/symmake_abld.cpp523
-rw-r--r--qmake/generators/symbian/symmake_abld.h68
-rw-r--r--qmake/generators/symbian/symmake_sbsv2.cpp760
-rw-r--r--qmake/generators/symbian/symmake_sbsv2.h84
-rw-r--r--qmake/generators/unix/unixmake.cpp925
-rw-r--r--qmake/generators/unix/unixmake.h84
-rw-r--r--qmake/generators/unix/unixmake2.cpp1352
-rw-r--r--qmake/generators/win32/borland_bmake.cpp175
-rw-r--r--qmake/generators/win32/borland_bmake.h68
-rw-r--r--qmake/generators/win32/mingw_make.cpp516
-rw-r--r--qmake/generators/win32/mingw_make.h88
-rw-r--r--qmake/generators/win32/msbuild_objectmodel.cpp1940
-rw-r--r--qmake/generators/win32/msbuild_objectmodel.h192
-rw-r--r--qmake/generators/win32/msvc_nmake.cpp361
-rw-r--r--qmake/generators/win32/msvc_nmake.h78
-rw-r--r--qmake/generators/win32/msvc_objectmodel.cpp2909
-rw-r--r--qmake/generators/win32/msvc_objectmodel.h1141
-rw-r--r--qmake/generators/win32/msvc_vcproj.cpp1569
-rw-r--r--qmake/generators/win32/msvc_vcproj.h151
-rw-r--r--qmake/generators/win32/msvc_vcxproj.cpp74
-rw-r--r--qmake/generators/win32/msvc_vcxproj.h70
-rw-r--r--qmake/generators/win32/winmakefile.cpp895
-rw-r--r--qmake/generators/win32/winmakefile.h96
-rw-r--r--qmake/generators/xmloutput.cpp378
-rw-r--r--qmake/generators/xmloutput.h244
-rw-r--r--qmake/main.cpp197
-rw-r--r--qmake/meta.cpp207
-rw-r--r--qmake/meta.h103
-rw-r--r--qmake/option.cpp813
-rw-r--r--qmake/option.h231
-rw-r--r--qmake/project.cpp3170
-rw-r--r--qmake/project.h196
-rw-r--r--qmake/property.cpp251
-rw-r--r--qmake/property.h72
-rw-r--r--qmake/qmake.pri162
-rw-r--r--qmake/qmake.pro36
-rw-r--r--qmake/qmake_pch.h71
62 files changed, 33268 insertions, 0 deletions
diff --git a/qmake/CHANGES b/qmake/CHANGES
new file mode 100644
index 0000000000..ee2927c7c7
--- /dev/null
+++ b/qmake/CHANGES
@@ -0,0 +1,99 @@
+2.10a -
+
+ support for spaces in filenames.
+
+2.00a -
+
+ Automatic feature loading (from CONFIG) has been added, this allows qmake to be
+ written using qmake language.
+
+ The dependency generation system has been redesigned to be faster (as over time
+ it had gotten slower and slower as features crept in). This new system is used
+ for dependency calcuation and moc detection.
+
+ qmake has been changed to allow features to be introduced without changes to
+ C++ sources (ie project files).
+
+ DEPENDS supported to allow hard coded dependencies (when qmake's depend are inadaquate)
+
+ $$sprintf() added to allow easy expansion of complex strings (using %1..%n)
+
+ for() iteration has been introduced to do simple looping in a qmake script.
+
+ CONFIG() test function added.
+
+ $$basename() and $$dirname() added for file manipulation.
+
+ warning() can be used in place of message() now.
+
+ improved support for subdirs with .pro's listed
+ support for QT added to add functionality from Qt
+
+1.07a -
+
+ support for precompiled headers added
+
+1.06b -
+
+ support for reading and writing libtool (.la) files
+ support for reading pkgconfig (.pkg) files
+
+ PWD added as an automatic variable to mean the directory
+ the file being parsed is in (this change required that the
+ directory be set to the file being parsed as well, function
+ tests that query relative paths will need to be relative the
+ file being parsed).
+
+ persistant data cache introduced
+
+1.05a -
+
+ caching of more information (speed ups)
+ $$list() added to be used as a lambda function in qmake
+ $$files() added to allow regular expression matching
+ $$fromfile() added to grab one single variable value from a parsed file
+ $$prompt() added to allow querying for user input from qmake
+ include() modified to support specifying which variables to import
+ equals() test added to test for equality
+ MSVC.net generator added [partial solution files in vcsubdirs]
+
+1.04a -
+
+ subdirs supports multiple project files in a single directory.
+
+1.03a -
+
+ New function $$system() to extract the value of a shell call.
+
+1.02a -
+
+ Dependency / Mocable caching. qmake can cache these expensive operations with qmake_cache
+ CONFIG.
+
+ The parser has been improved to cover more error cases, as well as more forgiving
+
+ qmake now includes a special else scope to invert the previous test
+
+ Ability to add user defined targets to UnixMakefiles.
+
+1.01a -
+
+ New system for library linking. This system allows a user several different features:
+
+ 1) libtool like library dependencies to static libraries build with qmake
+ 2) library dependencies, when on .pro depends on another library - it will
+ automatically build that other library (unix makefiles only)
+ 3) automatic detection of configurations for Qt, if CONFIG qt is specified
+ it will find the settings for the most recent Qt itself.
+
+ Project Builder for Mac OS X is now a supported backend for qmake.
+
+ qmake now offers a 'make uninstall' feature, to reverse the actions of a 'make install'.
+
+ qmake can now do recursive searches in project-file mode (-r option).
+
+1.00a -
+
+ First release, shipped with Qt 3.0.
+
+ qmake ships with support for Unix make, MSVC (both dsp and nmake), Borland make.
diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix
new file mode 100644
index 0000000000..9dbe035fc2
--- /dev/null
+++ b/qmake/Makefile.unix
@@ -0,0 +1,349 @@
+SOURCE_PATH = @SOURCE_PATH@
+BUILD_PATH = @BUILD_PATH@
+QTOBJS = @QMAKE_QTOBJS@
+QTSRCS = @QMAKE_QTSRCS@
+QMAKESPEC = @QMAKESPEC@
+LFLAGS = @QMAKE_LFLAGS@
+
+#qmake code
+OBJS=project.o property.o main.o makefile.o unixmake2.o unixmake.o \
+ mingw_make.o option.o winmakefile.o projectgenerator.o \
+ meta.o makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \
+ borland_bmake.o msvc_vcproj.o msvc_vcxproj.o msvc_nmake.o msvc_objectmodel.o msbuild_objectmodel.o \
+ symmake.o initprojectdeploy_symbian.o symmake_abld.o symmake_sbsv2.o \
+ symbiancommon.o registry.o epocroot.o gbuild.o
+
+#qt code
+QOBJS=qtextcodec.o qutfcodec.o qstring.o qtextstream.o qiodevice.o qmalloc.o qglobal.o \
+ qbytearray.o qbytearraymatcher.o qdatastream.o qbuffer.o qlist.o qfile.o \
+ qfilesystementry.o qfilesystemengine_unix.o qfilesystemengine.o qfilesystemiterator_unix.o \
+ qfsfileengine_unix.o qfsfileengine.o \
+ qfsfileengine_iterator.o qregexp.o qvector.o qbitarray.o qdir.o qdiriterator.o quuid.o qhash.o \
+ qfileinfo.o qdatetime.o qstringlist.o qabstractfileengine.o qtemporaryfile.o \
+ qmap.o qmetatype.o qsettings.o qsystemerror.o qlibraryinfo.o qvariant.o qvsnprintf.o \
+ qlocale.o qlocale_tools.o qlocale_unix.o qlinkedlist.o qurl.o qnumeric.o qcryptographichash.o \
+ qxmlstream.o qxmlutils.o \
+ $(QTOBJS)
+
+
+
+
+#all sources, used for the depend target
+DEPEND_SRC=project.cpp property.cpp meta.cpp main.cpp generators/makefile.cpp generators/unix/unixmake2.cpp \
+ generators/unix/unixmake.cpp generators/win32/winmakefile.cpp generators/projectgenerator.cpp \
+ generators/mac/pbuilder_pbx.cpp generators/mac/xmloutput.cpp generators/metamakefile.cpp \
+ generators/makefiledeps.cpp option.cpp generators/win32/mingw_make.cpp generators/makefile.cpp \
+ generators/win32/msvc_vcproj.cpp generators/win32/msvc_vcxproj.cpp generators/win32/msvc_objectmodel.cpp generators/win32/msbuild_objectmodel.cpp generators/win32/msbuild_objectmodel.cpp generators/win32/msvc_nmake.cpp generators/win32/borland_bmake.cpp \
+ generators/symbian/symmake.cpp generators/symbian/initprojectdeploy_symbian.cpp \
+ $(SOURCE_PATH)/tools/shared/windows/registry.cpp \
+ $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp \
+ generators/symbian/symmake_abld.cpp generators/symbian/symmake_sbsv2.cpp \
+ generaters/symbian/symbiancommon.cpp \
+ generators/integrity/gbuild.cpp \
+ $(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp $(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp \
+ $(SOURCE_PATH)/src/corelib/tools/qstring.cpp $(SOURCE_PATH)/src/corelib/io/qfile.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qtextstream.cpp $(SOURCE_PATH)/src/corelib/io/qiodevice.cpp \
+ $(SOURCE_PATH)/src/corelib/global/qmalloc.cpp \
+ $(SOURCE_PATH)/src/corelib/global/qglobal.cpp $(SOURCE_PATH)/src/corelib/tools/qregexp.cpp \
+ $(SOURCE_PATH)/src/corelib/tools/qbytearray.cpp $(SOURCE_PATH)/src/corelib/tools/qbytearraymatcher.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qdatastream.cpp $(SOURCE_PATH)/src/corelib/io/qbuffer.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_unix.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_mac.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_unix.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qfsfileengine_unix.cpp $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp $(SOURCE_PATH)/src/corelib/tools/qlist.cpp \
+ $(SOURCE_PATH)/src/corelib/tools/qvector.cpp $(SOURCE_PATH)/src/corelib/tools/qbitarray.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qdiriterator.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qdir.cpp $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qfileinfo.cpp $(SOURCE_PATH)/src/corelib/tools/qdatetime.cpp \
+ $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp $(SOURCE_PATH)/src/corelib/tools/qmap.cpp \
+ $(SOURCE_PATH)/src/corelib/global/qconfig.cpp $(SOURCE_PATH)/src/corelib/io/qurl.cpp \
+ $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp \
+ $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp \
+ $(SOURCE_PATH)/src/corelib/tools/qlocale_unix.cpp \
+ $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp \
+ $(SOURCE_PATH)/src/corelib/tools/qhash.cpp $(SOURCE_PATH)/src/corelib/kernel/qcore_mac.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp $(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp \
+ $(SOURCE_PATH)/src/corelib/io/qsettings.cpp $(SOURCE_PATH)/src/corelib/kernel/qvariant.cpp \
+ $(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp $(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp \
+ $(SOURCE_PATH)/src/corelib/tools/qvsnprintf.cpp $(SOURCE_PATH)/src/corelib/global/qnumeric.cpp \
+ $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp \
+ $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp \
+ $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp \
+ $(QTSRCS)
+
+CPPFLAGS = -g -I. -Igenerators -Igenerators/unix -Igenerators/win32 \
+ -Igenerators/mac -Igenerators/symbian -Igenerators/integrity \
+ -I$(BUILD_PATH)/include -I$(BUILD_PATH)/include/QtCore \
+ -I$(BUILD_PATH)/src/corelib/global -I$(BUILD_PATH)/src/corelib/xml \
+ -I$(SOURCE_PATH)/tools/shared \
+ -DQT_NO_PCRE \
+ -DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED -DQLIBRARYINFO_EPOCROOT \
+ -DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_NO_COMPONENT -DQT_NO_STL \
+ -DQT_NO_COMPRESS -I$(QMAKESPEC) -DHAVE_QCONFIG_CPP -DQT_NO_THREAD -DQT_NO_QOBJECT \
+ -DQT_NO_GEOM_VARIANT -DQT_NO_DEPRECATED $(OPENSOURCE_CXXFLAGS)
+
+CXXFLAGS = @QMAKE_CXXFLAGS@ $(CPPFLAGS)
+
+first all: $(BUILD_PATH)/bin/qmake
+qmake: $(BUILD_PATH)/bin/qmake
+
+$(BUILD_PATH)/bin/qmake: $(OBJS) $(QOBJS)
+ $(CXX) -o "$@" $(OBJS) $(QOBJS) $(LFLAGS)
+
+clean::
+ rm -f $(OBJS) $(QOBJS)
+
+distclean:: clean
+ rm -rf $(BUILD_PATH)/bin/qmake .deps
+
+depend:
+ makedepend -D__MAKEDEPEND__ $(CPPFLAGS) $(DEPEND_SRC)
+
+# don't use optimization for these
+qtextstream.o: $(SOURCE_PATH)/src/corelib/io/qtextstream.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qtextstream.cpp
+
+qvariant.o: $(SOURCE_PATH)/src/corelib/kernel/qvariant.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qvariant.cpp
+
+qsettings.o: $(SOURCE_PATH)/src/corelib/io/qsettings.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qsettings.cpp
+
+qsystemerror.o: $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp
+
+qlibraryinfo.o: $(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp
+
+qnumeric.o: $(SOURCE_PATH)/src/corelib/global/qnumeric.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qnumeric.cpp
+
+qsettings_mac.o: $(SOURCE_PATH)/src/corelib/io/qsettings_mac.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qsettings_mac.cpp
+
+qiodevice.o: $(SOURCE_PATH)/src/corelib/io/qiodevice.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qiodevice.cpp
+
+qmalloc.o: $(SOURCE_PATH)/src/corelib/global/qmalloc.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qmalloc.cpp
+
+qglobal.o: $(SOURCE_PATH)/src/corelib/global/qglobal.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qglobal.cpp
+
+qbytearray.o: $(SOURCE_PATH)/src/corelib/tools/qbytearray.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qbytearray.cpp
+
+qvsnprintf.o: $(SOURCE_PATH)/src/corelib/tools/qvsnprintf.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qvsnprintf.cpp
+
+qbytearraymatcher.o: $(SOURCE_PATH)/src/corelib/tools/qbytearraymatcher.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qbytearraymatcher.cpp
+
+qmetatype.o: $(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp
+
+qcore_mac.o: $(SOURCE_PATH)/src/corelib/kernel/qcore_mac.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qcore_mac.cpp
+
+qurl.o: $(SOURCE_PATH)/src/corelib/io/qurl.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qurl.cpp
+
+qutfcodec.o: $(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp
+
+qtextcodec.o: $(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp
+
+qstring.o: $(SOURCE_PATH)/src/corelib/tools/qstring.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qstring.cpp
+
+qlocale.o: $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp
+
+qlocale_tools.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp
+
+qlocale_unix.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_unix.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_unix.cpp
+
+qdatastream.o: $(SOURCE_PATH)/src/corelib/io/qdatastream.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qdatastream.cpp
+
+qbuffer.o: $(SOURCE_PATH)/src/corelib/io/qbuffer.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qbuffer.cpp
+
+qlist.o: $(SOURCE_PATH)/src/corelib/tools/qlist.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlist.cpp
+
+qfile.o: $(SOURCE_PATH)/src/corelib/io/qfile.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfile.cpp
+
+qfilesystementry.o: $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp
+
+qfilesystemengine.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp
+
+qfilesystemengine_unix.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_unix.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_unix.cpp
+
+qfilesystemengine_mac.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_mac.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_mac.cpp
+
+qfilesystemiterator_unix.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_unix.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_unix.cpp
+
+qfsfileengine.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp
+
+qfsfileengine_iterator.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator.cpp
+
+qfsfileengine_unix.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_unix.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_unix.cpp
+
+qabstractfileengine.o: $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp
+
+qtemporaryfile.o: $(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp
+
+qregexp.o: $(SOURCE_PATH)/src/corelib/tools/qregexp.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qregexp.cpp
+
+qvector.o: $(SOURCE_PATH)/src/corelib/tools/qvector.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qvector.cpp
+
+qbitarray.o: $(SOURCE_PATH)/src/corelib/tools/qbitarray.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qbitarray.cpp
+
+qdir.o: $(SOURCE_PATH)/src/corelib/io/qdir.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qdir.cpp
+
+qdiriterator.o: $(SOURCE_PATH)/src/corelib/io/qdiriterator.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qdiriterator.cpp
+
+quuid.o: $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp
+
+qfileinfo.o: $(SOURCE_PATH)/src/corelib/io/qfileinfo.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfileinfo.cpp
+
+qdatetime.o: $(SOURCE_PATH)/src/corelib/tools/qdatetime.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qdatetime.cpp
+
+qstringlist.o: $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp
+
+qmap.o: $(SOURCE_PATH)/src/corelib/tools/qmap.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qmap.cpp
+
+qhash.o: $(SOURCE_PATH)/src/corelib/tools/qhash.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qhash.cpp
+
+qlinkedlist.o: $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp
+
+winmakefile.o: generators/win32/winmakefile.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/winmakefile.cpp
+
+project.o: project.cpp project.h option.h
+ $(CXX) -c -o $@ $(CXXFLAGS) project.cpp
+
+property.o: property.cpp project.h option.h
+ $(CXX) -c -o $@ $(CXXFLAGS) property.cpp
+
+meta.o: meta.cpp project.h option.h
+ $(CXX) -c -o $@ $(CXXFLAGS) meta.cpp
+
+main.o: main.cpp project.h
+ $(CXX) -c -o $@ $(CXXFLAGS) main.cpp
+
+option.o: option.cpp option.h $(BUILD_PATH)/src/corelib/global/qconfig.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) option.cpp
+
+qcryptographichash.o: $(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp
+
+metamakefile.o: generators/metamakefile.cpp generators/symbian/symbian_makefile.h
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/metamakefile.cpp
+
+xmloutput.o: generators/xmloutput.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/xmloutput.cpp
+
+makefiledeps.o: generators/makefiledeps.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/makefiledeps.cpp
+
+makefile.o: generators/makefile.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/makefile.cpp
+
+unixmake.o: generators/unix/unixmake.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/unix/unixmake.cpp
+
+unixmake2.o: generators/unix/unixmake2.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/unix/unixmake2.cpp
+
+borland_bmake.o: generators/win32/borland_bmake.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/borland_bmake.cpp
+
+mingw_make.o: generators/win32/mingw_make.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/mingw_make.cpp
+
+msvc_objectmodel.o: generators/win32/msvc_objectmodel.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/msvc_objectmodel.cpp
+
+msvc_vcproj.o: generators/win32/msvc_vcproj.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/msvc_vcproj.cpp
+
+msbuild_objectmodel.o: generators/win32/msbuild_objectmodel.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/msbuild_objectmodel.cpp
+
+msvc_vcxproj.o: generators/win32/msvc_vcxproj.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/msvc_vcxproj.cpp
+
+msvc_nmake.o: generators/win32/msvc_nmake.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/msvc_nmake.cpp
+
+pbuilder_pbx.o: generators/mac/pbuilder_pbx.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/mac/pbuilder_pbx.cpp
+
+symmake.o: generators/symbian/symmake.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/symbian/symmake.cpp
+
+symmake_abld.o: generators/symbian/symmake_abld.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/symbian/symmake_abld.cpp
+
+symmake_sbsv2.o: generators/symbian/symmake_sbsv2.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/symbian/symmake_sbsv2.cpp
+
+symbiancommon.o: generators/symbian/symbiancommon.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/symbian/symbiancommon.cpp
+
+initprojectdeploy_symbian.o: generators/symbian/initprojectdeploy_symbian.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/symbian/initprojectdeploy_symbian.cpp
+
+registry.o: $(SOURCE_PATH)/tools/shared/windows/registry.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/tools/shared/windows/registry.cpp
+
+epocroot.o: $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp
+
+gbuild.o: generators/integrity/gbuild.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/integrity/gbuild.cpp
+
+projectgenerator.o: generators/projectgenerator.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) generators/projectgenerator.cpp
+
+qxmlstream.o: $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp
+
+qxmlutils.o: $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp
+
+#default rules
+.cpp.o:
+ $(CXX) -c -o $@ $(CXXFLAGS) $<
+
+# DO NOT DELETE THIS LINE -- make depend depends on it
diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32
new file mode 100644
index 0000000000..6fd393993e
--- /dev/null
+++ b/qmake/Makefile.win32
@@ -0,0 +1,218 @@
+!IF "$(QMAKESPEC)" == "win32-msvc" || "$(QMAKESPEC)" == "win32-msvc.net" || "$(QMAKESPEC)" == "win32-msvc2002" || "$(QMAKESPEC)" == "win32-msvc2003" || "$(QMAKESPEC)" == "win32-msvc2005" || "$(QMAKESPEC)" == "win32-msvc2008" || "$(QMAKESPEC)" == "win32-msvc2010" || "$(QMAKESPEC)" == "win32-icc"
+
+!if "$(SOURCE_PATH)" == ""
+SOURCE_PATH = ..
+!endif
+!if "$(BUILD_PATH)" == ""
+BUILD_PATH = ..
+!endif
+
+#
+# specific stuff for NMake and ICC
+#
+!if "$(QMAKESPEC)" == "win32-icc"
+CXX = icl
+LINK = link
+CFLAGS = /Zc:forScope
+!else
+CXX = cl
+LINK = link
+!endif
+
+#
+# specific stuff for VS2005
+#
+!if "$(QMAKESPEC)" == "win32-msvc2005"
+CFLAGS_EXTRA = /Zc:wchar_t-
+!elseif "$(QMAKESPEC)" == "win32-msvc2008" || "$(QMAKESPEC)" == "win32-msvc2010"
+CFLAGS_EXTRA = /MP
+!endif
+
+CFLAGS_BARE = -c -Fo./ \
+ -W3 -nologo -O2 \
+ $(CFLAGS_EXTRA) \
+ -I. -Igenerators -Igenerators\unix -Igenerators\win32 -Igenerators\mac -Igenerators\symbian -Igenerators\integrity \
+ -I$(BUILD_PATH)\include -I$(BUILD_PATH)\include\QtCore \
+ -I$(SOURCE_PATH)\include -I$(SOURCE_PATH)\include\QtCore \
+ -I$(BUILD_PATH)\src\corelib\global \
+ -I$(BUILD_PATH)\src\corelib\xml \
+ -I$(SOURCE_PATH)\mkspecs\$(QMAKESPEC) \
+ -I$(SOURCE_PATH)\tools\shared \
+ -DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_LITE_COMPONENT -DQT_NODLL -DQT_NO_STL \
+ -DQT_NO_COMPRESS -DUNICODE -DHAVE_QCONFIG_CPP -DQT_BUILD_QMAKE -DQT_NO_THREAD \
+ -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -DQT_NO_DATASTREAM -DQT_NO_PCRE -DQT_BOOTSTRAPPED \
+ -DQLIBRARYINFO_EPOCROOT
+CFLAGS = -Yuqmake_pch.h -FIqmake_pch.h -Fpqmake_pch.pch $(CFLAGS_BARE) $(CFLAGS)
+
+CXXFLAGS_BARE = $(CFLAGS_BARE)
+CXXFLAGS = $(CFLAGS)
+
+LFLAGS =
+LIBS = ole32.lib advapi32.lib
+LINKQMAKE = $(LINK) $(LFLAGS) -OUT:qmake.exe $(OBJS) $(QTOBJS) $(LIBS)
+ADDCLEAN = vc60.pdb vc70.pdb qmake.pdb qmake.ilk
+
+!ELSE
+!ERROR Unsupported compiler for this Makefile
+!ENDIF
+
+#qmake code
+OBJS = project.obj main.obj makefile.obj unixmake.obj unixmake2.obj mingw_make.obj \
+ option.obj winmakefile.obj projectgenerator.obj property.obj meta.obj \
+ makefiledeps.obj metamakefile.obj xmloutput.obj pbuilder_pbx.obj \
+ borland_bmake.obj msvc_nmake.obj msvc_vcproj.obj msvc_vcxproj.obj \
+ msvc_objectmodel.obj msbuild_objectmodel.obj symmake.obj initprojectdeploy_symbian.obj \
+ symmake_abld.obj symmake_sbsv2.obj symbiancommon.obj registry.obj epocroot.obj \
+ gbuild.obj
+
+!IFDEF QMAKE_OPENSOURCE_EDITION
+CFLAGS = $(CFLAGS) -DQMAKE_OPENSOURCE_EDITION
+!ENDIF
+
+#qt code
+QTOBJS= \
+ qbitarray.obj \
+ qbuffer.obj \
+ qcryptographichash.obj \
+ qfilesystementry.obj \
+ qfilesystemengine.obj \
+ qfilesystemengine_win.obj \
+ qfilesystemiterator_win.obj \
+ qfsfileengine.obj \
+ qfsfileengine_iterator.obj \
+ qbytearray.obj \
+ qvsnprintf.obj \
+ qbytearraymatcher.obj \
+ qdatetime.obj \
+ qdir.obj \
+ qdiriterator.obj \
+ qfile.obj \
+ qtemporaryfile.obj \
+ qabstractfileengine.obj \
+ qfsfileengine_win.obj \
+ qsystemlibrary.obj \
+ qfileinfo.obj \
+ qglobal.obj \
+ qhash.obj \
+ qiodevice.obj \
+ qlist.obj \
+ qlinkedlist.obj \
+ qlocale.obj \
+ qlocale_tools.obj \
+ qlocale_win.obj \
+ qmalloc.obj \
+ qmap.obj \
+ qregexp.obj \
+ qtextcodec.obj \
+ qutfcodec.obj \
+ qstring.obj \
+ qstringlist.obj \
+ qsystemerror.obj \
+ qtextstream.obj \
+ qdatastream.obj \
+ quuid.obj \
+ qvector.obj \
+ qsettings.obj \
+ qlibraryinfo.obj \
+ qvariant.obj \
+ qurl.obj \
+ qsettings_win.obj \
+ qmetatype.obj \
+ qxmlstream.obj \
+ qxmlutils.obj \
+ qnumeric.obj
+
+
+first all: qmake.exe
+
+qmake.exe: $(OBJS) $(QTOBJS)
+ $(LINKQMAKE) qmake_pch.obj
+ -copy qmake.exe $(BUILD_PATH)\bin\qmake.exe
+
+clean::
+ -del $(QTOBJS)
+ -del $(OBJS)
+ -del qmake_pch.obj
+ -del qmake_pch.pch
+ -del qsystemlibrary.obj
+ -del vc60.pdb
+ -del vc70.pdb
+ -del qmake.pdb
+ -del qmake.ilk
+ -del qmake.tds
+
+distclean:: clean
+ -del qmake
+
+.c.obj:
+ $(CXX) $(CFLAGS) $<
+
+.cpp.obj:
+ $(CXX) $(CXXFLAGS) $<
+
+.cc.obj:
+ $(CXX) $(CXXFLAGS) $<
+
+.cxx.obj:
+ $(CXX) $(CXXFLAGS) $<
+
+$(OBJS): qmake_pch.obj
+
+qsystemlibrary.obj: $(SOURCE_PATH)\src\corelib\plugin\qsystemlibrary.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)\src\corelib\plugin\qsystemlibrary.cpp
+
+$(QTOBJS): qmake_pch.obj
+
+qmake_pch.obj:
+ $(CXX) $(CXXFLAGS_BARE) -c -Yc -Fpqmake_pch.pch -TP qmake_pch.h
+
+{$(SOURCE_PATH)\qmake\generators\mac}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\qmake\generators\symbian}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\qmake\generators\integrity}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\qmake\generators\unix}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\qmake\generators\win32}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\qmake\generators}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\qmake}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\src\3rdparty\md5}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\src\corelib\codecs}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\src\corelib\global}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\src\corelib\io}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\src\corelib\kernel}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\src\corelib\plugin}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\src\corelib\tools}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\src\corelib\xml}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\tools\shared\symbian}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
+
+{$(SOURCE_PATH)\tools\shared\windows}.cpp{}.obj::
+ $(CXX) $(CXXFLAGS) $<
diff --git a/qmake/Makefile.win32-g++ b/qmake/Makefile.win32-g++
new file mode 100644
index 0000000000..d40dc29a9b
--- /dev/null
+++ b/qmake/Makefile.win32-g++
@@ -0,0 +1,360 @@
+ifeq "$(SOURCE_PATH)" ""
+SOURCE_PATH = ..
+endif
+
+#cmd version
+
+ifeq "$(BUILD_PATH)" ""
+BUILD_PATH = ..
+endif
+
+#
+# specific stuff for mingw g++ make
+#
+CXX = g++
+CFLAGS = -c -o$@ -O \
+ -I. -Igenerators -Igenerators/unix \
+ -Igenerators/win32 -Igenerators/mac \
+ -Igenerators/symbian -Igenerators/integrity \
+ -I$(BUILD_PATH)/include -I$(BUILD_PATH)/include/QtCore \
+ -I$(SOURCE_PATH)/include -I$(SOURCE_PATH)/include/QtCore \
+ -I$(BUILD_PATH)/src/corelib/global \
+ -I$(BUILD_PATH)/src/corelib/xml \
+ -I$(SOURCE_PATH)/mkspecs/win32-g++ \
+ -I$(SOURCE_PATH)/tools/shared \
+ -DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_LITE_COMPONENT -DQT_NO_PCRE \
+ -DQT_NODLL -DQT_NO_STL -DQT_NO_COMPRESS -DUNICODE -DHAVE_QCONFIG_CPP \
+ -DQT_BUILD_QMAKE -DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -DQT_NO_DATASTREAM \
+ -DQT_BOOTSTRAPPED -DQLIBRARYINFO_EPOCROOT
+CXXFLAGS = $(CFLAGS)
+LFLAGS = -static-libgcc -static-libstdc++ -s
+LIBS = -lole32 -luuid -ladvapi32 -lkernel32
+LINKQMAKE = g++ $(LFLAGS) -o qmake.exe $(OBJS) $(QTOBJS) $(LIBS)
+ADDCLEAN =
+
+
+#qmake code
+OBJS = project.o main.o makefile.o unixmake.o unixmake2.o mingw_make.o \
+ option.o winmakefile.o projectgenerator.o property.o meta.o \
+ makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \
+ borland_bmake.o msvc_nmake.o msvc_vcproj.o msvc_vcxproj.o \
+ msvc_objectmodel.o msbuild_objectmodel.o symmake.o initprojectdeploy_symbian.o \
+ symmake_abld.o symmake_sbsv2.o symbiancommon.o registry.o epocroot.o gbuild.o
+
+ifdef QMAKE_OPENSOURCE_EDITION
+CFLAGS += -DQMAKE_OPENSOURCE_EDITION
+endif
+
+#qt code
+QTOBJS= \
+ qbitarray.o \
+ qbuffer.o \
+ qbytearray.o \
+ qcryptographichash.o \
+ qvsnprintf.o \
+ qbytearraymatcher.o \
+ qconfig.o \
+ qdatetime.o \
+ qdir.o \
+ qdiriterator.o \
+ qfile.o \
+ qtemporaryfile.o \
+ qfileinfo.o \
+ qabstractfileengine.o \
+ qfilesystementry.o \
+ qfilesystemengine.o \
+ qfilesystemengine_win.o \
+ qfilesystemiterator_win.o \
+ qfsfileengine.o \
+ qfsfileengine_iterator.o \
+ qfsfileengine_win.o \
+ qglobal.o \
+ qhash.o \
+ qiodevice.o \
+ qlibraryinfo.o \
+ qlist.o \
+ qlinkedlist.o \
+ qlocale.o \
+ qlocale_tools.o \
+ qlocale_win.o \
+ qmalloc.o \
+ qmap.o \
+ qregexp.o \
+ qtextcodec.o \
+ qutfcodec.o \
+ qstring.o \
+ qstringlist.o \
+ qsystemerror.o \
+ qsystemlibrary.o \
+ qtextstream.o \
+ quuid.o \
+ qvector.o \
+ qurl.o \
+ qsettings.o \
+ qsettings_win.o \
+ qvariant.o \
+ qmetatype.o \
+ qxmlstream.o \
+ qxmlutils.o \
+ qnumeric.o
+
+
+qmake.exe: $(OBJS) $(QTOBJS)
+ $(LINKQMAKE)
+ -copy qmake.exe $(BUILD_PATH)\bin\qmake.exe
+
+Makefile: Makefile.win32-g++
+ @echo "Out of date, please rerun configure"
+
+clean::
+ -del $(OBJS) $(QTOBJS) $(ADDCLEAN)
+
+distclean:: clean
+ -del qmake
+
+.c.o:
+ $(CXX) $(CFLAGS) $<
+
+.cpp.o:
+ $(CXX) $(CXXFLAGS) $<
+
+qconfig.o: $(BUILD_PATH)/src/corelib/global/qconfig.cpp
+ $(CXX) $(CXXFLAGS) $(BUILD_PATH)/src/corelib/global/qconfig.cpp
+
+qsettings_win.o: $(SOURCE_PATH)/src/corelib/io/qsettings_win.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qsettings_win.cpp
+
+qsettings.o: $(SOURCE_PATH)/src/corelib/io/qsettings.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qsettings.cpp
+
+qvariant.o: $(SOURCE_PATH)/src/corelib/kernel/qvariant.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qvariant.cpp
+
+qurl.o: $(SOURCE_PATH)/src/corelib/io/qurl.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qurl.cpp
+
+qtextstream.o: $(SOURCE_PATH)/src/corelib/io/qtextstream.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qtextstream.cpp
+
+qdatastream.o: $(SOURCE_PATH)/src/corelib/io/qdatastream.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qdatastream.cpp
+
+qiodevice.o: $(SOURCE_PATH)/src/corelib/io/qiodevice.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qiodevice.cpp
+
+qlibraryinfo.o: $(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp
+
+qnumeric.o: $(SOURCE_PATH)/src/corelib/global/qnumeric.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qnumeric.cpp
+
+qmalloc.o: $(SOURCE_PATH)/src/corelib/global/qmalloc.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qmalloc.cpp
+
+qglobal.o: $(SOURCE_PATH)/src/corelib/global/qglobal.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qglobal.cpp
+
+qhash.o: $(SOURCE_PATH)/src/corelib/tools/qhash.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qhash.cpp
+
+qbytearray.o: $(SOURCE_PATH)/src/corelib/tools/qbytearray.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qbytearray.cpp
+
+qcryptographichash.o: $(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp
+
+qvsnprintf.o: $(SOURCE_PATH)/src/corelib/tools/qvsnprintf.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qvsnprintf.cpp
+
+qbytearraymatcher.o: $(SOURCE_PATH)/src/corelib/tools/qbytearraymatcher.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qbytearraymatcher.cpp
+
+qutfcodec.o: $(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp
+
+qstring.o: $(SOURCE_PATH)/src/corelib/tools/qstring.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qstring.cpp
+
+qlocale.o: $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp
+
+qlocale_tools.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp
+
+qlocale_win.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_win.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_win.cpp
+
+quuid.o: $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp
+
+qbuffer.o: $(SOURCE_PATH)/src/corelib/io/qbuffer.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qbuffer.cpp
+
+qlist.o: $(SOURCE_PATH)/src/corelib/tools/qlist.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlist.cpp
+
+qlinkedlist.o: $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp
+
+qfile.o: $(SOURCE_PATH)/src/corelib/io/qfile.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfile.cpp
+
+qtemporaryfile.o: $(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp
+
+qabstractfileengine.o: $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp
+
+qfilesystementry.o: $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp
+
+qfilesystemengine.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp
+
+qfilesystemengine_win.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_win.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_win.cpp
+
+qfilesystemiterator_win.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_win.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_win.cpp
+
+qfsfileengine_win.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_win.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_win.cpp
+
+qfsfileengine.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp
+
+qfsfileengine_iterator.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator.cpp
+
+qtextcodec.o: $(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp
+
+qregexp.o: $(SOURCE_PATH)/src/corelib/tools/qregexp.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qregexp.cpp
+
+qvector.o: $(SOURCE_PATH)/src/corelib/tools/qvector.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qvector.cpp
+
+qbitarray.o: $(SOURCE_PATH)/src/corelib/tools/qbitarray.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qbitarray.cpp
+
+qdir.o: $(SOURCE_PATH)/src/corelib/io/qdir.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qdir.cpp
+
+qdiriterator.o: $(SOURCE_PATH)/src/corelib/io/qdiriterator.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qdiriterator.cpp
+
+qmetatype.o: $(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp
+
+qfileinfo.o: $(SOURCE_PATH)/src/corelib/io/qfileinfo.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfileinfo.cpp
+
+qdatetime.o: $(SOURCE_PATH)/src/corelib/tools/qdatetime.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qdatetime.cpp
+
+qstringlist.o: $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp
+
+qsystemerror.o: $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp
+
+qsystemlibrary.o: $(SOURCE_PATH)/src/corelib/plugin/qsystemlibrary.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/plugin/qsystemlibrary.cpp
+
+qmap.o: $(SOURCE_PATH)/src/corelib/tools/qmap.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qmap.cpp
+
+makefile.o: $(SOURCE_PATH)/qmake/generators/makefile.cpp
+ $(CXX) $(CXXFLAGS) generators/makefile.cpp
+
+unixmake.o: $(SOURCE_PATH)/qmake/generators/unix/unixmake.cpp
+ $(CXX) $(CXXFLAGS) generators/unix/unixmake.cpp
+
+unixmake2.o: $(SOURCE_PATH)/qmake/generators/unix/unixmake2.cpp
+ $(CXX) $(CXXFLAGS) generators/unix/unixmake2.cpp
+
+winmakefile.o: $(SOURCE_PATH)/qmake/generators/win32/winmakefile.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/winmakefile.cpp
+
+borland_bmake.o: $(SOURCE_PATH)/qmake/generators/win32/borland_bmake.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/borland_bmake.cpp
+
+mingw_make.o: $(SOURCE_PATH)/qmake/generators/win32/mingw_make.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/mingw_make.cpp
+
+msvc_nmake.o: $(SOURCE_PATH)/qmake/generators/win32/msvc_nmake.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/msvc_nmake.cpp
+
+msvc_vcproj.o: $(SOURCE_PATH)/qmake/generators/win32/msvc_vcproj.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/msvc_vcproj.cpp
+
+msvc_objectmodel.o: $(SOURCE_PATH)/qmake/generators/win32/msvc_objectmodel.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/msvc_objectmodel.cpp
+
+msvc_vcxproj.o: $(SOURCE_PATH)/qmake/generators/win32/msvc_vcxproj.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/msvc_vcxproj.cpp
+
+msbuild_objectmodel.o: $(SOURCE_PATH)/qmake/generators/win32/msbuild_objectmodel.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/msbuild_objectmodel.cpp
+
+symmake.o: $(SOURCE_PATH)/qmake/generators/symbian/symmake.cpp
+ $(CXX) $(CXXFLAGS) generators/symbian/symmake.cpp
+
+symmake_abld.o: $(SOURCE_PATH)/qmake/generators/symbian/symmake_abld.cpp
+ $(CXX) $(CXXFLAGS) generators/symbian/symmake_abld.cpp
+
+symmake_sbsv2.o: $(SOURCE_PATH)/qmake/generators/symbian/symmake_sbsv2.cpp
+ $(CXX) $(CXXFLAGS) generators/symbian/symmake_sbsv2.cpp
+
+symbiancommon.o: $(SOURCE_PATH)/qmake/generators/symbian/symbiancommon.cpp
+ $(CXX) $(CXXFLAGS) generators/symbian/symbiancommon.cpp
+
+initprojectdeploy_symbian.o: $(SOURCE_PATH)/qmake/generators/symbian/initprojectdeploy_symbian.cpp
+ $(CXX) $(CXXFLAGS) generators/symbian/initprojectdeploy_symbian.cpp
+
+registry.o: $(SOURCE_PATH)/tools/shared/windows/registry.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/tools/shared/windows/registry.cpp
+
+epocroot.o: $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp
+
+gbuild.o: $(SOURCE_PATH)/qmake/generators/integrity/gbuild.cpp
+ $(CXX) $(CXXFLAGS) generators/integrity/gbuild.cpp
+
+project.o: $(SOURCE_PATH)/qmake/project.cpp $(SOURCE_PATH)/qmake/project.h $(SOURCE_PATH)/qmake/option.h
+ $(CXX) $(CXXFLAGS) project.cpp
+
+meta.o: $(SOURCE_PATH)/qmake/meta.cpp $(SOURCE_PATH)/qmake/project.h $(SOURCE_PATH)/qmake/option.h
+ $(CXX) $(CXXFLAGS) meta.cpp
+
+main.o: $(SOURCE_PATH)/qmake/main.cpp $(SOURCE_PATH)/qmake/project.h
+ $(CXX) $(CXXFLAGS) main.cpp
+
+option.o: $(SOURCE_PATH)/qmake/option.cpp $(SOURCE_PATH)/qmake/option.h
+ $(CXX) $(CXXFLAGS) option.cpp
+
+property.o: $(SOURCE_PATH)/qmake/property.cpp $(SOURCE_PATH)/qmake/project.h $(SOURCE_PATH)/qmake/option.h
+ $(CXX) $(CXXFLAGS) property.cpp
+
+projectgenerator.o: $(SOURCE_PATH)/qmake/generators/projectgenerator.cpp
+ $(CXX) $(CXXFLAGS) generators/projectgenerator.cpp
+
+pbuilder_pbx.o: $(SOURCE_PATH)/qmake/generators/mac/pbuilder_pbx.cpp
+ $(CXX) $(CXXFLAGS) generators/mac/pbuilder_pbx.cpp
+
+makefiledeps.o: $(SOURCE_PATH)/qmake/generators/makefiledeps.cpp
+ $(CXX) $(CXXFLAGS) generators/makefiledeps.cpp
+
+metamakefile.o: $(SOURCE_PATH)/qmake/generators/metamakefile.cpp $(SOURCE_PATH)/qmake/generators/symbian/symbian_makefile.h
+ $(CXX) $(CXXFLAGS) generators/metamakefile.cpp
+
+xmloutput.o: $(SOURCE_PATH)/qmake/generators/xmloutput.cpp
+ $(CXX) $(CXXFLAGS) generators/xmloutput.cpp
+
+qxmlstream.o: $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp
+
+qxmlutils.o: $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp
+
diff --git a/qmake/Makefile.win32-g++-sh b/qmake/Makefile.win32-g++-sh
new file mode 100644
index 0000000000..49ccfbcc77
--- /dev/null
+++ b/qmake/Makefile.win32-g++-sh
@@ -0,0 +1,359 @@
+ifeq "$(SOURCE_PATH)" ""
+SOURCE_PATH = ..
+endif
+
+#sh version
+
+ifeq "$(BUILD_PATH)" ""
+BUILD_PATH = ..
+endif
+
+#
+# specific stuff for mingw g++ make
+#
+CXX = g++
+CFLAGS = -c -o$@ -O \
+ -I. -Igenerators -Igenerators/unix \
+ -Igenerators/win32 -Igenerators/mac \
+ -Igenerators/symbian -Igenerators/integrity \
+ -I$(BUILD_PATH)/include -I$(BUILD_PATH)/include/QtCore \
+ -I$(SOURCE_PATH)/include -I$(SOURCE_PATH)/include/QtCore \
+ -I$(BUILD_PATH)/src/corelib/global \
+ -I$(BUILD_PATH)/src/corelib/xml \
+ -I$(SOURCE_PATH)/mkspecs/win32-g++ \
+ -I$(SOURCE_PATH)/tools/shared \
+ -DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_LITE_COMPONENT -DQT_NO_PCRE \
+ -DQT_NODLL -DQT_NO_STL -DQT_NO_COMPRESS -DUNICODE -DHAVE_QCONFIG_CPP \
+ -DQT_BUILD_QMAKE -DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -DQT_NO_DATASTREAM \
+ -DQT_BOOTSTRAPPED -DQLIBRARYINFO_EPOCROOT
+CXXFLAGS = $(CFLAGS)
+LFLAGS = -static-libgcc -static-libstdc++ -s
+LIBS = -lole32 -luuid -ladvapi32 -lkernel32
+LINKQMAKE = g++ $(LFLAGS) -o qmake.exe $(OBJS) $(QTOBJS) $(LIBS)
+ADDCLEAN =
+
+
+#qmake code
+OBJS = project.o main.o makefile.o unixmake.o unixmake2.o mingw_make.o \
+ option.o winmakefile.o projectgenerator.o property.o meta.o \
+ makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \
+ borland_bmake.o msvc_nmake.o msvc_vcproj.o msvc_vcxproj.o \
+ msvc_objectmodel.o msbuild_objectmodel.o symmake.o initprojectdeploy_symbian.o \
+ symmake_abld.o symmake_sbsv2.o symbiancommon.o registry.o epocroot.o gbuild.o
+
+ifdef QMAKE_OPENSOURCE_EDITION
+CFLAGS += -DQMAKE_OPENSOURCE_EDITION
+endif
+
+#qt code
+QTOBJS= \
+ qbitarray.o \
+ qbuffer.o \
+ qbytearray.o \
+ qcryptographichash.o \
+ qvsnprintf.o \
+ qbytearraymatcher.o \
+ qconfig.o \
+ qdatetime.o \
+ qdir.o \
+ qdiriterator.o \
+ qfile.o \
+ qtemporaryfile.o \
+ qfileinfo.o \
+ qabstractfileengine.o \
+ qfilesystementry.o \
+ qfilesystemengine.o \
+ qfilesystemengine_win.o \
+ qfilesystemiterator_win.o \
+ qfsfileengine.o \
+ qfsfileengine_iterator.o \
+ qfsfileengine_win.o \
+ qglobal.o \
+ qhash.o \
+ qiodevice.o \
+ qlibraryinfo.o \
+ qlist.o \
+ qlinkedlist.o \
+ qlocale.o \
+ qlocale_tools.o \
+ qlocale_win.o \
+ qmalloc.o \
+ qmap.o \
+ qregexp.o \
+ qtextcodec.o \
+ qutfcodec.o \
+ qstring.o \
+ qstringlist.o \
+ qsystemlibrary.o \
+ qsystemerror.o \
+ qtextstream.o \
+ quuid.o \
+ qvector.o \
+ qurl.o \
+ qsettings.o \
+ qsettings_win.o \
+ qvariant.o \
+ qmetatype.o \
+ qxmlstream.o \
+ qxmlutils.o \
+ qnumeric.o
+
+qmake.exe: $(OBJS) $(QTOBJS)
+ $(LINKQMAKE)
+ -cp qmake.exe $(BUILD_PATH)/bin/qmake.exe
+
+Makefile: Makefile.win32-g++-sh
+ @echo "Out of date, please rerun configure"
+
+clean::
+ -del $(OBJS) $(QTOBJS) $(ADDCLEAN)
+
+distclean:: clean
+ -del qmake
+
+.c.o:
+ $(CXX) $(CFLAGS) $<
+
+.cpp.o:
+ $(CXX) $(CXXFLAGS) $<
+
+qconfig.o: $(BUILD_PATH)/src/corelib/global/qconfig.cpp
+ $(CXX) $(CXXFLAGS) $(BUILD_PATH)/src/corelib/global/qconfig.cpp
+
+qsettings_win.o: $(SOURCE_PATH)/src/corelib/io/qsettings_win.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qsettings_win.cpp
+
+qsettings.o: $(SOURCE_PATH)/src/corelib/io/qsettings.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qsettings.cpp
+
+qvariant.o: $(SOURCE_PATH)/src/corelib/kernel/qvariant.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qvariant.cpp
+
+qurl.o: $(SOURCE_PATH)/src/corelib/io/qurl.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qurl.cpp
+
+qtextstream.o: $(SOURCE_PATH)/src/corelib/io/qtextstream.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qtextstream.cpp
+
+qdatastream.o: $(SOURCE_PATH)/src/corelib/io/qdatastream.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qdatastream.cpp
+
+qiodevice.o: $(SOURCE_PATH)/src/corelib/io/qiodevice.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qiodevice.cpp
+
+qlibraryinfo.o: $(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qlibraryinfo.cpp
+
+qnumeric.o: $(SOURCE_PATH)/src/corelib/global/qnumeric.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qnumeric.cpp
+
+qmalloc.o: $(SOURCE_PATH)/src/corelib/global/qmalloc.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qmalloc.cpp
+
+qglobal.o: $(SOURCE_PATH)/src/corelib/global/qglobal.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qglobal.cpp
+
+qhash.o: $(SOURCE_PATH)/src/corelib/tools/qhash.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qhash.cpp
+
+qbytearray.o: $(SOURCE_PATH)/src/corelib/tools/qbytearray.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qbytearray.cpp
+
+qcryptographichash.o: $(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp
+
+qvsnprintf.o: $(SOURCE_PATH)/src/corelib/tools/qvsnprintf.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qvsnprintf.cpp
+
+qbytearraymatcher.o: $(SOURCE_PATH)/src/corelib/tools/qbytearraymatcher.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qbytearraymatcher.cpp
+
+qutfcodec.o: $(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp
+
+qstring.o: $(SOURCE_PATH)/src/corelib/tools/qstring.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qstring.cpp
+
+qlocale.o: $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale.cpp
+
+qlocale_tools.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_tools.cpp
+
+qlocale_win.o: $(SOURCE_PATH)/src/corelib/tools/qlocale_win.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlocale_win.cpp
+
+quuid.o: $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/plugin/quuid.cpp
+
+qbuffer.o: $(SOURCE_PATH)/src/corelib/io/qbuffer.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qbuffer.cpp
+
+qlist.o: $(SOURCE_PATH)/src/corelib/tools/qlist.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlist.cpp
+
+qlinkedlist.o: $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp
+
+qfile.o: $(SOURCE_PATH)/src/corelib/io/qfile.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfile.cpp
+
+qtemporaryfile.o: $(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp
+
+qabstractfileengine.o: $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qabstractfileengine.cpp
+
+qfilesystementry.o: $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystementry.cpp
+
+qfilesystemengine.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine.cpp
+
+qfilesystemengine_win.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_win.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemengine_win.cpp
+
+qfilesystemiterator_win.o: $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_win.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfilesystemiterator_win.cpp
+
+qfsfileengine_win.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_win.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_win.cpp
+
+qfsfileengine.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine.cpp
+
+qfsfileengine_iterator.o: $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfsfileengine_iterator.cpp
+
+qtextcodec.o: $(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp
+
+qregexp.o: $(SOURCE_PATH)/src/corelib/tools/qregexp.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qregexp.cpp
+
+qvector.o: $(SOURCE_PATH)/src/corelib/tools/qvector.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qvector.cpp
+
+qbitarray.o: $(SOURCE_PATH)/src/corelib/tools/qbitarray.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qbitarray.cpp
+
+qdir.o: $(SOURCE_PATH)/src/corelib/io/qdir.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qdir.cpp
+
+qdiriterator.o: $(SOURCE_PATH)/src/corelib/io/qdiriterator.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qdiriterator.cpp
+
+qmetatype.o: $(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp
+
+qfileinfo.o: $(SOURCE_PATH)/src/corelib/io/qfileinfo.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qfileinfo.cpp
+
+qdatetime.o: $(SOURCE_PATH)/src/corelib/tools/qdatetime.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qdatetime.cpp
+
+qstringlist.o: $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qstringlist.cpp
+
+qsystemerror.o: $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp
+
+qsystemlibrary.o: $(SOURCE_PATH)/src/corelib/plugin/qsystemlibrary.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/plugin/qsystemlibrary.cpp
+
+qmap.o: $(SOURCE_PATH)/src/corelib/tools/qmap.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qmap.cpp
+
+makefile.o: $(SOURCE_PATH)/qmake/generators/makefile.cpp
+ $(CXX) $(CXXFLAGS) generators/makefile.cpp
+
+unixmake.o: $(SOURCE_PATH)/qmake/generators/unix/unixmake.cpp
+ $(CXX) $(CXXFLAGS) generators/unix/unixmake.cpp
+
+unixmake2.o: $(SOURCE_PATH)/qmake/generators/unix/unixmake2.cpp
+ $(CXX) $(CXXFLAGS) generators/unix/unixmake2.cpp
+
+winmakefile.o: $(SOURCE_PATH)/qmake/generators/win32/winmakefile.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/winmakefile.cpp
+
+borland_bmake.o: $(SOURCE_PATH)/qmake/generators/win32/borland_bmake.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/borland_bmake.cpp
+
+mingw_make.o: $(SOURCE_PATH)/qmake/generators/win32/mingw_make.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/mingw_make.cpp
+
+msvc_nmake.o: $(SOURCE_PATH)/qmake/generators/win32/msvc_nmake.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/msvc_nmake.cpp
+
+msvc_vcproj.o: $(SOURCE_PATH)/qmake/generators/win32/msvc_vcproj.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/msvc_vcproj.cpp
+
+msvc_objectmodel.o: $(SOURCE_PATH)/qmake/generators/win32/msvc_objectmodel.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/msvc_objectmodel.cpp
+
+msvc_vcxproj.o: $(SOURCE_PATH)/qmake/generators/win32/msvc_vcxproj.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/msvc_vcxproj.cpp
+
+msbuild_objectmodel.o: $(SOURCE_PATH)/qmake/generators/win32/msbuild_objectmodel.cpp
+ $(CXX) $(CXXFLAGS) generators/win32/msbuild_objectmodel.cpp
+
+symmake.o: $(SOURCE_PATH)/qmake/generators/symbian/symmake.cpp
+ $(CXX) $(CXXFLAGS) generators/symbian/symmake.cpp
+
+symmake_abld.o: $(SOURCE_PATH)/qmake/generators/symbian/symmake_abld.cpp
+ $(CXX) $(CXXFLAGS) generators/symbian/symmake_abld.cpp
+
+symmake_sbsv2.o: $(SOURCE_PATH)/qmake/generators/symbian/symmake_sbsv2.cpp
+ $(CXX) $(CXXFLAGS) generators/symbian/symmake_sbsv2.cpp
+
+symbiancommon.o: $(SOURCE_PATH)/qmake/generators/symbian/symbiancommon.cpp
+ $(CXX) $(CXXFLAGS) generators/symbian/symbiancommon.cpp
+
+initprojectdeploy_symbian.o: $(SOURCE_PATH)/qmake/generators/symbian/initprojectdeploy_symbian.cpp
+ $(CXX) $(CXXFLAGS) generators/symbian/initprojectdeploy_symbian.cpp
+
+registry.o: $(SOURCE_PATH)/tools/shared/windows/registry.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/tools/shared/windows/registry.cpp
+
+epocroot.o: $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp
+
+gbuild.o: $(SOURCE_PATH)/qmake/generators/integrity/gbuild.cpp
+ $(CXX) $(CXXFLAGS) generators/integrity/gbuild.cpp
+
+
+project.o: $(SOURCE_PATH)/qmake/project.cpp $(SOURCE_PATH)/qmake/project.h $(SOURCE_PATH)/qmake/option.h
+ $(CXX) $(CXXFLAGS) project.cpp
+
+meta.o: $(SOURCE_PATH)/qmake/meta.cpp $(SOURCE_PATH)/qmake/project.h $(SOURCE_PATH)/qmake/option.h
+ $(CXX) $(CXXFLAGS) meta.cpp
+
+main.o: $(SOURCE_PATH)/qmake/main.cpp $(SOURCE_PATH)/qmake/project.h
+ $(CXX) $(CXXFLAGS) main.cpp
+
+option.o: $(SOURCE_PATH)/qmake/option.cpp $(SOURCE_PATH)/qmake/option.h
+ $(CXX) $(CXXFLAGS) option.cpp
+
+property.o: $(SOURCE_PATH)/qmake/property.cpp $(SOURCE_PATH)/qmake/project.h $(SOURCE_PATH)/qmake/option.h
+ $(CXX) $(CXXFLAGS) property.cpp
+
+projectgenerator.o: $(SOURCE_PATH)/qmake/generators/projectgenerator.cpp
+ $(CXX) $(CXXFLAGS) generators/projectgenerator.cpp
+
+pbuilder_pbx.o: $(SOURCE_PATH)/qmake/generators/mac/pbuilder_pbx.cpp
+ $(CXX) $(CXXFLAGS) generators/mac/pbuilder_pbx.cpp
+
+makefiledeps.o: $(SOURCE_PATH)/qmake/generators/makefiledeps.cpp
+ $(CXX) $(CXXFLAGS) generators/makefiledeps.cpp
+
+metamakefile.o: $(SOURCE_PATH)/qmake/generators/metamakefile.cpp $(SOURCE_PATH)/qmake/generators/symbian/symbian_makefile.h
+ $(CXX) $(CXXFLAGS) generators/metamakefile.cpp
+
+xmloutput.o: $(SOURCE_PATH)/qmake/generators/xmloutput.cpp
+ $(CXX) $(CXXFLAGS) generators/xmloutput.cpp
+
+qxmlstream.o: $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp
+
+qxmlutils.o: $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp
+ $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp
diff --git a/qmake/cachekeys.h b/qmake/cachekeys.h
new file mode 100644
index 0000000000..b29e4f211f
--- /dev/null
+++ b/qmake/cachekeys.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CACHEKEYS_H
+#define CACHEKEYS_H
+
+#include "project.h"
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qhash.h>
+
+QT_BEGIN_NAMESPACE
+
+// -------------------------------------------------------------------------------------------------
+struct FixStringCacheKey
+{
+ mutable uint hash;
+ QString string, pwd;
+ uchar flags;
+ FixStringCacheKey(const QString &s, uchar f)
+ {
+ hash = 0;
+ pwd = qmake_getpwd();
+ string = s;
+ flags = f;
+ }
+ bool operator==(const FixStringCacheKey &f) const
+ {
+ return (hashCode() == f.hashCode() &&
+ f.flags == flags &&
+ f.string == string &&
+ f.pwd == pwd);
+ }
+ inline uint hashCode() const {
+ if(!hash)
+ hash = qHash(string) | qHash(flags) /*| qHash(pwd)*/;
+ return hash;
+ }
+};
+inline uint qHash(const FixStringCacheKey &f) { return f.hashCode(); }
+
+// -------------------------------------------------------------------------------------------------
+struct FileInfoCacheKey
+{
+ mutable uint hash;
+ QString file, pwd;
+ FileInfoCacheKey(const QString &f)
+ {
+ hash = 0;
+ if(isRelativePath(f))
+ pwd = qmake_getpwd();
+ file = f;
+ }
+ bool operator==(const FileInfoCacheKey &f) const
+ {
+ return (hashCode() == f.hashCode() && f.file == file &&
+ f.pwd == pwd);
+ }
+ inline uint hashCode() const {
+ if(!hash)
+ hash = qHash(file) /*| qHash(pwd)*/;
+ return hash;
+ }
+ inline bool isRelativePath(const QString &file) {
+ int length = file.length();
+ if (!length)
+ return true;
+
+ const QChar c0 = file.at(0);
+ const QChar c1 = length >= 2 ? file.at(1) : QChar(0);
+ return !(c0 == QLatin1Char('/')
+ || c0 == QLatin1Char('\\')
+ || (c0.isLetter() && c1 == QLatin1Char(':'))
+ || (c0 == QLatin1Char('/') && c1 == QLatin1Char('/'))
+ || (c0 == QLatin1Char('\\') && c1 == QLatin1Char('\\')));
+ }
+};
+inline uint qHash(const FileInfoCacheKey &f) { return f.hashCode(); }
+
+// -------------------------------------------------------------------------------------------------
+template <typename T>
+inline void qmakeDeleteCacheClear(void *i) { delete reinterpret_cast<T*>(i); }
+
+inline void qmakeFreeCacheClear(void *i) { free(i); }
+
+typedef void (*qmakeCacheClearFunc)(void *);
+void qmakeAddCacheClear(qmakeCacheClearFunc func, void **);
+void qmakeClearCaches();
+
+QT_END_NAMESPACE
+
+#endif // CACHEKEYS_H
diff --git a/qmake/generators/integrity/gbuild.cpp b/qmake/generators/integrity/gbuild.cpp
new file mode 100644
index 0000000000..17bd8f0e5a
--- /dev/null
+++ b/qmake/generators/integrity/gbuild.cpp
@@ -0,0 +1,442 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gbuild.h"
+#include "option.h"
+#include "meta.h"
+#include <qdir.h>
+#include <qregexp.h>
+#include <qcryptographichash.h>
+#include <qdebug.h>
+#include <stdlib.h>
+#include <time.h>
+#ifdef Q_OS_UNIX
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+unsigned int dllbase = 0x01000000;
+#define DLLOFFSET 0x600000
+
+GBuildMakefileGenerator::GBuildMakefileGenerator() : MakefileGenerator()
+{
+ nativebins << "moc" << "rcc" << "uic" << "bootstrap";
+}
+
+bool
+GBuildMakefileGenerator::write()
+{
+ QStringList tmp;
+ QString filename(Option::output.fileName());
+ QString pathtoremove(qmake_getpwd());
+ QString relpath(pathtoremove);
+ QString strtarget(project->first("TARGET"));
+ bool isnativebin = nativebins.contains(strtarget);
+ relpath.replace(Option::output_dir, "");
+
+ /* correct output for non-prl, non-recursive case */
+ QString outname(qmake_getpwd());
+ outname += QDir::separator();
+ outname += fileInfo(Option::output.fileName()).baseName();
+ outname += projectSuffix();
+ Option::output.close();
+ Option::output.setFileName(outname);
+ MakefileGenerator::openOutput(Option::output, QString());
+
+ if (strtarget != fileInfo(project->projectFile()).baseName()) {
+ QString gpjname(strtarget);
+ QString outputName(qmake_getpwd());
+ outputName += QDir::separator();
+ outputName += fileInfo(project->projectFile()).baseName();
+ outputName += projectSuffix();
+ QFile f(outputName);
+ f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
+ QTextStream t(&f);
+ t << "#!gbuild\n";
+ t << "[Project]\n";
+ t << gpjname << projectSuffix() << "\n";
+ if ((project->first("TEMPLATE") == "lib")
+ && project->isActiveConfig("shared"))
+ t << gpjname << "_shared" << projectSuffix() << "\n";
+ t.flush();
+ gpjname += projectSuffix();
+ Option::output.close();
+ Option::output.setFileName(gpjname);
+ MakefileGenerator::openOutput(Option::output, QString());
+ }
+
+ if ((project->first("TEMPLATE") == "app")
+ && (!isnativebin)) {
+ QTextStream t(&Option::output);
+ QString intname(strtarget);
+ intname += ".int";
+ /* this is for bulding an INTEGRITY application.
+ * generate the .int integrate file and the .gpj INTEGRITY Application
+ * project file, then go on with regular files */
+ t << "#!gbuild" << "\n";
+ t << "[INTEGRITY Application]" << "\n";
+ t << "\t:binDirRelative=.\n";
+ t << "\t-o " << strtarget << "\n";
+ t << intname << "\n";
+ t << strtarget << "_app" << projectSuffix() << "\n";
+ t.flush();
+
+ /* generate integrate file */
+ QFile f(intname);
+ f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
+ QTextStream ti(&f);
+ ti << "# This is a file automatically generated by qmake" << "\n";
+ ti << "# Modifications will be lost next time you run qmake" << "\n";
+ ti << "Kernel" << "\n";
+ ti << "\tFilename\tDynamicDownload" << "\n";
+ ti << "EndKernel" << "\n" << "\n";
+ ti << "AddressSpace" << "\n";
+ ti << "\tName\t" << strtarget << "\n";
+ ti << "\tFilename\t" << strtarget << "_app" << "\n";
+ ti << "\tMemoryPoolSize\t0x100000" << "\n";
+ ti << "\tLanguage\tC++" << "\n";
+ /* FIXME : heap size is huge to be big enough for every example
+ * it should probably be tailored for each example, btu there is no
+ * good way to guess that */
+ ti << "\tHeapSize\t0x00D00000" << "\n";
+ ti << "\tTask\tInitial" << "\n";
+ ti << "\t\tStackSize\t0x30000" << "\n";
+ ti << "\tEndTask" << "\n";
+ ti << "EndAddressSpace" << "\n";
+ ti.flush();
+
+ /* change current project file to <projectname>_app.gpj and continue
+ * generation */
+ filename.insert(filename.lastIndexOf("."), "_app");
+ Option::output.close();
+ Option::output.setFileName(filename);
+ MakefileGenerator::openOutput(Option::output, QString());
+ } else if ((project->first("TEMPLATE") == "lib")
+ && project->isActiveConfig("shared")) {
+ QString gpjname(strtarget);
+ gpjname += "_shared";
+ gpjname += projectSuffix();
+ QFile f(gpjname);
+ f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
+ QTextStream t(&f);
+ t << "#!gbuild\n"
+ "[Program]\n"
+ "\t-A libINTEGRITY.so\n"
+ "\t-A libc.so\n"
+ "\t-A libscxx.so\n"
+ "\t-A libQtCore.so\n"
+ "\t-e __ghsbegin_text\n"
+ "\t-startfile=-\n"
+ "\t:syslibraries=-\n"
+ "\t-Onolink\n";
+ t << "\t-o lib" << strtarget << ".so\n";
+ t << "\t-l" << strtarget << "\n";
+ t << "\t-extractall=-l" << strtarget << "\n";
+ t << "\t:outputDir=work/" << filename.section(QDir::separator(), 0, -1).remove(".gpj") << "\n";
+ t << strtarget << "_shared.ld\n";
+ t << "$(__OS_DIR)/intlib/sharedobjbssinit.c\n";
+ t.flush();
+
+ QFile fl(strtarget + "_shared.ld");
+ fl.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
+ QTextStream tl(&fl);
+ tl << "CONSTANTS {\n"
+ " __INTEGRITY_MinPageAlign = 16K\n"
+ " __INTEGRITY_MaxPageAlign = 16K\n"
+ " __INTEGRITY_LibCBaseAddress = \n";
+ tl << dllbase << "\n";
+ tl << "}\n"
+ "-sec\n"
+ "{\n"
+ " .picbase __INTEGRITY_LibCBaseAddress :\n"
+ " .text :\n"
+ " .syscall :\n"
+ " .intercall :\n"
+ " .interfunc :\n"
+ " .secinfo :\n"
+ " .rodata align(16) :\n"
+ " .fixaddr :\n"
+ " .fixtype :\n"
+ " .rombeg :\n"
+ " .textchecksum :\n"
+ " // The above sections may be large. Leave a bigger gap for large pages.\n"
+ " .pidbase align(__INTEGRITY_MaxPageAlign) :\n"
+ " .sdabase :\n"
+ " .data :\n"
+ " .toc :\n"
+ " .opd :\n"
+ " .datachecksum :\n"
+ " .bss align(__INTEGRITY_MinPageAlign) :\n"
+ " .heap :\n"
+ "}\n";
+ tl.flush();
+ dllbase += DLLOFFSET;
+ }
+
+ warn_msg(WarnParser, Option::output.fileName().toAscii());
+ QTextStream t(&Option::output);
+ QString primaryTarget(project->values("QMAKE_CXX").at(0));
+
+ pathtoremove += QDir::separator();
+ filename.remove(qmake_getpwd());
+
+ //HEADER
+ t << "#!gbuild" << "\n";
+
+ /* find the architecture out of the compiler name */
+ if (filename.endsWith("projects.gpj")) {
+ primaryTarget.remove(0, 5);
+ t << "macro QT_BUILD_DIR=%expand_path(.)\n";
+ t << "macro __OS_DIR=" << project->values("INTEGRITY_DIR").first() << "\n";
+ t << "primaryTarget=" << primaryTarget << "_integrity.tgt" << "\n";
+ t << "customization=util/integrity/qt.bod\n";
+ }
+ /* project type */
+ if (project->first("TEMPLATE") == "app") {
+ t << "[Program]" << "\n";
+ if (isnativebin) {
+ t << "\t:binDir=bin\n";
+ t << "\t-o " << strtarget << "\n";
+ } else {
+ t << "\t:binDirRelative=.\n";
+ t << "\t-o " << strtarget << "_app\n";
+ }
+ } else if (project->first("TEMPLATE") == "lib") {
+ t << "[Library]" << "\n";
+ t << "\t:binDir=lib" << "\n";
+ t << "\t-o lib" << strtarget << ".a" << "\n";
+ } else if (project->first("TEMPLATE") == "subdirs")
+ t << "[Project]" << "\n";
+ else
+ t << project->first("TEMPLATE") << "\n";
+
+ /* compilations options */
+ t << "\t:sourceDir=." << "\n";
+
+ t << "\t:outputDir=work" << relpath << "\n";
+ if (filename.endsWith("projects.gpj")) {
+ t << "\t:sourceDir=work\n";
+ t << "\t-Iwork\n";
+ t << "\t-Llib\n";
+ t << "\t";
+ QStringList &l = project->values("QMAKE_CXXFLAGS");
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ if ((*it).startsWith("-"))
+ t << "\n" << "\t" << (*it);
+ else
+ t << " " << (*it);
+ }
+ t << "\n";
+ }
+ t << "\n";
+
+ t << varGlue("DEFINES", "\t-D", "\n\t-D", "\n");
+
+ t << "\t-I.\n\t-I" << specdir() << "\n";
+ t << varGlue("INCLUDEPATH", "\t-I", "\n\t-I", "\n");
+ t << "\t--cxx_include_directory .\n\t--cxx_include_directory " << specdir() << "\n";
+ t << varGlue("INCLUDEPATH", "\t--cxx_include_directory ", "\n\t--cxx_include_directory ", "\n");
+
+ if (project->first("TEMPLATE") == "app") {
+ /* include linker flags if it's an application */
+ QString src[] = { "QMAKE_LFLAGS", "QMAKE_FRAMEWORKPATH_FLAGS", "QMAKE_LIBDIR_FLAGS", "QMAKE_LIBS", "LIBS", QString() };
+ for (int i = 0; !src[i].isNull(); i++) {
+ /* skip target libraries for native tools */
+ if (isnativebin && (i == 0))
+ continue;
+ t << "\t";
+ QStringList &l = project->values(src[i]);
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ if ((*it).startsWith("-"))
+ t << "\n" << "\t" << (*it);
+ else
+ t << " " << (*it);
+ }
+ t << "\n";
+ }
+ }
+
+ /* first subdirectories/subprojects */
+ {
+ QStringList &l = project->values("SUBDIRS");
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString gpjname((*it));
+ /* avoid native tools */
+ if (nativebins.contains(gpjname.section("_", -1)))
+ continue;
+ if (!project->first((*it) + ".subdir").isEmpty())
+ gpjname = project->first((*it) + ".subdir");
+ else
+ gpjname.replace("_", QDir::separator());
+ gpjname += QDir::separator() + gpjname.section(QDir::separator(), -1);
+ gpjname += projectSuffix();
+ /* make relative */
+ if (!project->values("QT_SOURCE_TREE").isEmpty()) {
+ gpjname.replace(project->values("QT_SOURCE_TREE").first() + QDir::separator(), "");
+ }
+ t << gpjname << "\n";
+ }
+ }
+
+ {
+ QStringList &l = project->values("RESOURCES");
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString tmpstr((*it).replace(pathtoremove, ""));
+ t << tmpstr << "\t[Qt Resource]\n";
+ tmpstr = tmpstr.section(".", -2, -1).section(QDir::separator(), -1);
+ tmpstr.remove(".qrc");
+ t << "\t-name " << tmpstr << "\n";
+ tmpstr.insert(tmpstr.lastIndexOf(QDir::separator()) + 1, "qrc_");
+ tmpstr.append(".cpp");
+ t << "\t-o work/" << tmpstr << "\n";
+ }
+ }
+ {
+ QStringList &l = project->values("FORMS");
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString tmpstr((*it).replace(pathtoremove, ""));
+ t << tmpstr << "\t[Qt Dialog]\n";
+ tmpstr = tmpstr.section(".", 0, 0).section(QDir::separator(), -1);
+ tmpstr.insert(tmpstr.lastIndexOf(QDir::separator()) + 1, "ui_");
+ tmpstr.remove(".ui");
+ tmpstr.append(".h");
+ t << "\t-o work/" << tmpstr << "\n";
+ }
+ }
+
+ /* source files for this project */
+ QString src[] = { "HEADERS", "SOURCES", QString() };
+ for (int i = 0; !src[i].isNull(); i++) {
+ QStringList &l = project->values(src[i]);
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ if ((*it).isEmpty())
+ continue;
+ /* native tools aren't preprocessed */
+ if (!isnativebin)
+ t << writeOne((*it), pathtoremove);
+ else
+ t << (*it).remove(pathtoremove) << "\n";
+ }
+ }
+ t << "\n";
+
+ {
+ QStringList &l = project->values("GENERATED_SOURCES");
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ t << "work/" << (*it).section(QDir::separator(), -1) << "\n";
+ }
+ }
+
+ return true;
+}
+
+QString GBuildMakefileGenerator::writeOne(QString filename, QString pathtoremove)
+{
+ QString s("");
+ s += filename.remove(pathtoremove);
+ if (filename.endsWith(Option::h_ext.first())) {
+ QString corename(filename.section(QDir::separator(), -1));
+ corename.remove(Option::h_ext.first());
+ corename.append(Option::cpp_ext.first());
+ corename.prepend(Option::h_moc_mod);
+ s += "\t[MOC/Qt Header]\n";
+ s += "\t-o ";
+ s += "work/";
+ s += corename;
+ s += "\n";
+ } else if (filename.section(QDir::separator(), -1).startsWith("qrc_")) {
+ QString tmpstr(filename.section("/", -1).section(".", 0, -1).remove("qrc_").remove(".cpp"));
+ s += "\n\t:depends=";
+ s += tmpstr;
+ s += ".qrc";
+ s += "\n";
+ } else if (filename.endsWith(Option::cpp_ext.first())) {
+ QString tmpstr(filename.section("/", -1));
+// QString moctool(project->values("QMAKE_MOC").first());
+ QString filepath(pathtoremove);
+ if (!project->values("QT_SOURCE_TREE").isEmpty()) {
+ filepath.remove(project->values("QT_SOURCE_TREE").first());
+ filepath.remove(0, 1);
+ }
+// if (!project->values("QT_BUILD_TREE").isEmpty()) {
+// moctool.remove(project->values("QT_BUILD_TREE").first());
+// moctool.remove(0, 1);
+// }
+ s += "\n\t:preexecShellSafe='${QT_BUILD_DIR}/bin/moc ";
+// s += moctool;
+// s += " ";
+ s += varGlue("DEFINES", "-D", " -D", " ");
+ s += varGlue("INCLUDEPATH", "-I", " -I", " ");
+ s += filepath;
+ s += filename;
+ s += " -o ";
+ tmpstr.replace(Option::cpp_ext.first(), Option::cpp_moc_ext);
+ s += "work/";
+ s += tmpstr;
+ s += "\n";
+ } else
+ s += "\n";
+ return s;
+}
+
+bool
+GBuildMakefileGenerator::openOutput(QFile &file, const QString &build) const
+{
+ debug_msg(1, "file is %s", file.fileName().toLatin1().constData());
+ QFileInfo fi(file);
+ if (fi.filePath().isEmpty())
+ file.setFileName(qmake_getpwd() + QDir::separator() + file.fileName());
+ if (!file.fileName().endsWith(projectSuffix())) {
+ QString outputName(file.fileName());
+ outputName += QDir::separator();
+ outputName += fileInfo(project->projectFile()).baseName();
+ outputName += projectSuffix();
+ warn_msg(WarnParser, outputName.toAscii());
+ file.setFileName(outputName);
+ }
+ debug_msg(1, "file is %s", file.fileName().toLatin1().constData());
+ bool ret = MakefileGenerator::openOutput(file, QString());
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/integrity/gbuild.h b/qmake/generators/integrity/gbuild.h
new file mode 100644
index 0000000000..6b5b1a0a91
--- /dev/null
+++ b/qmake/generators/integrity/gbuild.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GBUILD_H
+#define GBUILD_H
+
+#include "makefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class GBuildMakefileGenerator : public MakefileGenerator
+{
+ virtual bool write();
+
+ QString projectSuffix() const { return QString(".gpj"); };
+ QString writeOne(QString filename, QString pathtoremove = "");
+
+public:
+ GBuildMakefileGenerator();
+ ~GBuildMakefileGenerator();
+
+ virtual bool supportsMetaBuild() { return false; }
+ virtual bool openOutput(QFile &, const QString &) const;
+protected:
+ bool doPrecompiledHeaders() const { return false; }
+ virtual bool doDepends() const { return true; }
+ QStringList nativebins;
+
+};
+
+inline GBuildMakefileGenerator::~GBuildMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // GBUILD_H
diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp
new file mode 100644
index 0000000000..19667cdbe4
--- /dev/null
+++ b/qmake/generators/mac/pbuilder_pbx.cpp
@@ -0,0 +1,1861 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pbuilder_pbx.h"
+#include "option.h"
+#include "meta.h"
+#include <qdir.h>
+#include <qregexp.h>
+#include <qcryptographichash.h>
+#include <qdebug.h>
+#include <stdlib.h>
+#include <time.h>
+#ifdef Q_OS_UNIX
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+#ifdef Q_OS_DARWIN
+#include <ApplicationServices/ApplicationServices.h>
+#include <private/qcore_mac_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//#define GENERATE_AGGREGRATE_SUBDIR
+
+// Note: this is fairly hacky, but it does the job...
+
+static QString qtMD5(const QByteArray &src)
+{
+ QByteArray digest = QCryptographicHash::hash(src, QCryptographicHash::Md5);
+ return QString::fromLatin1(digest.toHex());
+}
+
+ProjectBuilderMakefileGenerator::ProjectBuilderMakefileGenerator() : UnixMakefileGenerator()
+{
+
+}
+
+bool
+ProjectBuilderMakefileGenerator::writeMakefile(QTextStream &t)
+{
+ writingUnixMakefileGenerator = false;
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ /* for now just dump, I need to generated an empty xml or something.. */
+ fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
+ var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
+ return true;
+ }
+
+ project->values("MAKEFILE").clear();
+ project->values("MAKEFILE").append("Makefile");
+ if(project->first("TEMPLATE") == "app" || project->first("TEMPLATE") == "lib")
+ return writeMakeParts(t);
+ else if(project->first("TEMPLATE") == "subdirs")
+ return writeSubDirs(t);
+ return false;
+}
+
+struct ProjectBuilderSubDirs {
+ QMakeProject *project;
+ QString subdir;
+ bool autoDelete;
+ ProjectBuilderSubDirs(QMakeProject *p, QString s, bool a=true) : project(p), subdir(s), autoDelete(a) { }
+ ~ProjectBuilderSubDirs() {
+ if(autoDelete)
+ delete project;
+ }
+};
+
+bool
+ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
+{
+ if(project->isActiveConfig("generate_pbxbuild_makefile")) {
+ QString mkwrap = fileFixify(pbx_dir + Option::dir_sep + ".." + Option::dir_sep + project->first("MAKEFILE"),
+ qmake_getpwd());
+ QFile mkwrapf(mkwrap);
+ if(mkwrapf.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ debug_msg(1, "pbuilder: Creating file: %s", mkwrap.toLatin1().constData());
+ QTextStream mkwrapt(&mkwrapf);
+ writingUnixMakefileGenerator = true;
+ UnixMakefileGenerator::writeSubDirs(mkwrapt);
+ writingUnixMakefileGenerator = false;
+ }
+ }
+
+ //HEADER
+ const int pbVersion = pbuilderVersion();
+ t << "// !$*UTF8*$!" << "\n"
+ << "{" << "\n"
+ << "\t" << writeSettings("archiveVersion", "1", SettingsNoQuote) << ";" << "\n"
+ << "\t" << "classes = {" << "\n" << "\t" << "};" << "\n"
+ << "\t" << writeSettings("objectVersion", QString::number(pbVersion), SettingsNoQuote) << ";" << "\n"
+ << "\t" << "objects = {" << endl;
+
+ //SUBDIRS
+ QList<ProjectBuilderSubDirs*> pb_subdirs;
+ pb_subdirs.append(new ProjectBuilderSubDirs(project, QString(), false));
+ QString oldpwd = qmake_getpwd();
+ QMap<QString, QStringList> groups;
+ for(int pb_subdir = 0; pb_subdir < pb_subdirs.size(); ++pb_subdir) {
+ ProjectBuilderSubDirs *pb = pb_subdirs[pb_subdir];
+ const QStringList subdirs = pb->project->values("SUBDIRS");
+ for(int subdir = 0; subdir < subdirs.count(); subdir++) {
+ QString tmp = subdirs[subdir];
+ if(!pb->project->isEmpty(tmp + ".file"))
+ tmp = pb->project->first(tmp + ".file");
+ else if(!pb->project->isEmpty(tmp + ".subdir"))
+ tmp = pb->project->first(tmp + ".subdir");
+ if(fileInfo(tmp).isRelative() && !pb->subdir.isEmpty()) {
+ QString subdir = pb->subdir;
+ if(!subdir.endsWith(Option::dir_sep))
+ subdir += Option::dir_sep;
+ tmp = subdir + tmp;
+ }
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS(tmp, true)));
+ if(fi.exists()) {
+ if(fi.isDir()) {
+ QString profile = tmp;
+ if(!profile.endsWith(Option::dir_sep))
+ profile += Option::dir_sep;
+ profile += fi.baseName() + Option::pro_ext;
+ fi = QFileInfo(profile);
+ }
+ QMakeProject tmp_proj;
+ QString dir = fi.path(), fn = fi.fileName();
+ if(!dir.isEmpty()) {
+ if(!qmake_setpwd(dir))
+ fprintf(stderr, "Cannot find directory: %s\n", dir.toLatin1().constData());
+ }
+ if(tmp_proj.read(fn)) {
+ if(Option::debug_level) {
+ debug_msg(1, "Dumping all variables:");
+ QMap<QString, QStringList> &vars = tmp_proj.variables();
+ for(QMap<QString, QStringList>::Iterator it = vars.begin();
+ it != vars.end(); ++it) {
+ if(it.key().left(1) != "." && !it.value().isEmpty())
+ debug_msg(1, "%s: %s === %s", fn.toLatin1().constData(), it.key().toLatin1().constData(),
+ it.value().join(" :: ").toLatin1().constData());
+ }
+ }
+ if(tmp_proj.first("TEMPLATE") == "subdirs") {
+ QMakeProject *pp = new QMakeProject(&tmp_proj);
+ pp->read(0);
+ pb_subdirs += new ProjectBuilderSubDirs(pp, dir);
+ } else if(tmp_proj.first("TEMPLATE") == "app" || tmp_proj.first("TEMPLATE") == "lib") {
+ QString pbxproj = qmake_getpwd() + Option::dir_sep + tmp_proj.first("TARGET") + projectSuffix();
+ if(!exists(pbxproj)) {
+ warn_msg(WarnLogic, "Ignored (not found) '%s'", pbxproj.toLatin1().constData());
+ goto nextfile; // # Dirty!
+ }
+ const QString project_key = keyFor(pbxproj + "_PROJECTREF");
+ project->values("QMAKE_PBX_SUBDIRS") += pbxproj;
+ //PROJECTREF
+ {
+ bool in_root = true;
+ QString name = qmake_getpwd();
+ if(project->isActiveConfig("flat")) {
+ QString flat_file = fileFixify(name, oldpwd, Option::output_dir, FileFixifyRelative);
+ if(flat_file.indexOf(Option::dir_sep) != -1) {
+ QStringList dirs = flat_file.split(Option::dir_sep);
+ name = dirs.back();
+ }
+ } else {
+ QString flat_file = fileFixify(name, oldpwd, Option::output_dir, FileFixifyRelative);
+ if(QDir::isRelativePath(flat_file) && flat_file.indexOf(Option::dir_sep) != -1) {
+ QString last_grp("QMAKE_SUBDIR_PBX_HEIR_GROUP");
+ QStringList dirs = flat_file.split(Option::dir_sep);
+ name = dirs.back();
+ for(QStringList::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
+ QString new_grp(last_grp + Option::dir_sep + (*dir_it)), new_grp_key(keyFor(new_grp));
+ if(dir_it == dirs.begin()) {
+ if(!groups.contains(new_grp))
+ project->values("QMAKE_SUBDIR_PBX_GROUPS").append(new_grp_key);
+ } else {
+ if(!groups[last_grp].contains(new_grp_key))
+ groups[last_grp] += new_grp_key;
+ }
+ last_grp = new_grp;
+ }
+ groups[last_grp] += project_key;
+ in_root = false;
+ }
+ }
+ if(in_root)
+ project->values("QMAKE_SUBDIR_PBX_GROUPS") += project_key;
+ t << "\t\t" << project_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("lastKnownFileType", "wrapper.pb-project") << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(tmp_proj.first("TARGET") + projectSuffix())) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", pbxproj) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "<absolute>") << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ //WRAPPER
+ t << "\t\t" << keyFor(pbxproj + "_WRAPPER") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXReferenceProxy", SettingsNoQuote) << ";" << "\n";
+ if(tmp_proj.first("TEMPLATE") == "app") {
+ t << "\t\t\t" << writeSettings("fileType", "wrapper.application") << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", tmp_proj.first("TARGET") + ".app") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("fileType", "compiled.mach-o.dylib") << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", tmp_proj.first("TARGET") + ".dylib") << ";" << "\n";
+ }
+ t << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("remoteRef", keyFor(pbxproj + "_WRAPPERREF")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ t << "\t\t" << keyFor(pbxproj + "_WRAPPERREF") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("containerPortal", project_key) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXContainerItemProxy", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("proxyType", "2") << ";" << "\n"
+// << "\t\t\t" << writeSettings("remoteGlobalIDString", keyFor(pbxproj + "QMAKE_PBX_REFERENCE")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("remoteGlobalIDString", keyFor(pbxproj + "QMAKE_PBX_REFERENCE!!!")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("remoteInfo", tmp_proj.first("TARGET")) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ //PRODUCTGROUP
+ t << "\t\t" << keyFor(pbxproj + "_PRODUCTGROUP") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", project->values(pbxproj + "_WRAPPER"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Products") << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "<group>") << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+#ifdef GENERATE_AGGREGRATE_SUBDIR
+ //TARGET (for aggregate)
+ {
+ //container
+ const QString container_proxy = keyFor(pbxproj + "_CONTAINERPROXY");
+ t << "\t\t" << container_proxy << " = {" << "\n"
+ << "\t\t\t" << writeSettings("containerPortal", project_key) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXContainerItemProxy", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("proxyType", "1") << ";" << "\n"
+ << "\t\t\t" << writeSettings("remoteGlobalIDString", keyFor(pbxproj + "QMAKE_PBX_TARGET")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("remoteInfo", tmp_proj.first("TARGET")) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ //targetref
+ t << "\t\t" << keyFor(pbxproj + "_TARGETREF") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXTargetDependency", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", fixForOutput(tmp_proj.first("TARGET") +" (from " + tmp_proj.first("TARGET") + projectSuffix() + ")")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("targetProxy", container_proxy) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+#endif
+ }
+ }
+ nextfile:
+ qmake_setpwd(oldpwd);
+ }
+ }
+ }
+ qDeleteAll(pb_subdirs);
+ pb_subdirs.clear();
+
+ for(QMap<QString, QStringList>::Iterator grp_it = groups.begin(); grp_it != groups.end(); ++grp_it) {
+ t << "\t\t" << keyFor(grp_it.key()) << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("children", grp_it.value(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(grp_it.key().section(Option::dir_sep, -1))) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER
+ //BUILDSTYLE
+ QString active_buildstyle;
+ for(int as_release = 0; as_release < 2; as_release++)
+ {
+ QMap<QString, QString> settings;
+ settings.insert("COPY_PHASE_STRIP", (as_release ? "YES" : "NO"));
+ if(as_release)
+ settings.insert("GCC_GENERATE_DEBUGGING_SYMBOLS", "NO");
+ if(project->isActiveConfig("sdk") && !project->isEmpty("QMAKE_MAC_SDK"))
+ settings.insert("SDKROOT", project->first("QMAKE_MAC_SDK"));
+ {
+ const QStringList &l = project->values("QMAKE_MAC_XCODE_SETTINGS");
+ for(int i = 0; i < l.size(); ++i) {
+ QString name = l.at(i);
+ const QString value = project->values(name + QLatin1String(".value")).join(QString(Option::field_sep));
+ if(!project->isEmpty(name + QLatin1String(".name")))
+ name = project->values(name + QLatin1String(".name")).first();
+ settings.insert(name, value);
+ }
+ }
+
+ QString name;
+ if(pbVersion >= 42)
+ name = (as_release ? "Release" : "Debug");
+ else
+ name = (as_release ? "Deployment" : "Development");
+ if(pbVersion >= 42) {
+ QString key = keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_" + name);
+ project->values("QMAKE_SUBDIR_PBX_BUILDCONFIGS").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "XCBuildConfiguration", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n";
+ for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
+ t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";" << "\n";
+ t << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ QString key = keyFor("QMAKE_SUBDIR_PBX_BUILDSTYLE_" + name);
+ if(project->isActiveConfig("debug") != (bool)as_release) {
+ project->values("QMAKE_SUBDIR_PBX_BUILDSTYLES").append(key);
+ active_buildstyle = name;
+ } else if(pbVersion >= 42) {
+ project->values("QMAKE_SUBDIR_PBX_BUILDSTYLES").append(key);
+ }
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildRules", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n";
+ for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
+ t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";\n";
+ t << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildStyle", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ if(pbVersion >= 42) {
+ t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_LIST") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "XCConfigurationList", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildConfigurations", project->values("QMAKE_SUBDIR_PBX_BUILDCONFIGS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("defaultConfigurationIsVisible", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("defaultConfigurationIsName", active_buildstyle) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+#ifdef GENERATE_AGGREGRATE_SUBDIR
+ //target
+ t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_AGGREGATE_TARGET") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildPhases", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n"
+ << "\t\t\t\t" << writeSettings("PRODUCT_NAME", project->values("TARGET").first()) << ";" << "\n"
+ << "\t\t\t" << "};" << "\n";
+ {
+ QStringList dependencies;
+ const QStringList &qmake_subdirs = project->values("QMAKE_PBX_SUBDIRS");
+ for(int i = 0; i < qmake_subdirs.count(); i++)
+ dependencies += keyFor(qmake_subdirs[i] + "_TARGETREF");
+ t << "\t\t\t" << writeSettings("dependencies", dependencies, SettingsAsList, 4) << ";" << "\n"
+ }
+ t << "\t\t\t" << writeSettings("isa", "PBXAggregateTarget", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", project->values("TARGET").first()) << ";" << "\n"
+ << "\t\t\t" << writeSettings("productName", project->values("TARGET").first()) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+#endif
+
+ //ROOT_GROUP
+ t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_ROOT_GROUP") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", project->values("QMAKE_SUBDIR_PBX_GROUPS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "<group>") << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+
+
+ //ROOT
+ t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_ROOT") << " = {" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n"
+ << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("buildStyles", project->values("QMAKE_SUBDIR_PBX_BUILDSTYLES"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXProject", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("mainGroup", keyFor("QMAKE_SUBDIR_PBX_ROOT_GROUP")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("projectDirPath", QStringList()) << ";" << "\n";
+ if(pbVersion >= 42)
+ t << "\t\t\t" << writeSettings("buildConfigurationList", keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_LIST")) << ";" << "\n";
+ t << "\t\t\t" << "projectReferences = (" << "\n";
+ {
+ QStringList &qmake_subdirs = project->values("QMAKE_PBX_SUBDIRS");
+ for(int i = 0; i < qmake_subdirs.count(); i++) {
+ QString subdir = qmake_subdirs[i];
+ t << "\t\t\t\t" << "{" << "\n"
+ << "\t\t\t\t\t" << writeSettings("ProductGroup", keyFor(subdir + "_PRODUCTGROUP")) << ";" << "\n"
+ << "\t\t\t\t\t" << writeSettings("ProjectRef", keyFor(subdir + "_PROJECTREF")) << ";" << "\n"
+ << "\t\t\t\t" << "}," << "\n";
+ }
+ }
+ t << "\t\t\t" << ");" << "\n"
+ << "\t\t\t" << writeSettings("targets",
+#ifdef GENERATE_AGGREGRATE_SUBDIR
+ project->values("QMAKE_SUBDIR_AGGREGATE_TARGET"),
+#else
+ QStringList(),
+#endif
+ SettingsAsList, 4) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+
+ //FOOTER
+ t << "\t" << "};" << "\n"
+ << "\t" << writeSettings("rootObject", keyFor("QMAKE_SUBDIR_PBX_ROOT")) << ";" << "\n"
+ << "}" << endl;
+
+ return true;
+}
+
+class ProjectBuilderSources
+{
+ bool buildable, object_output;
+ QString key, group, compiler;
+public:
+ ProjectBuilderSources(const QString &key, bool buildable=false, const QString &group=QString(), const QString &compiler=QString(), bool producesObject=false);
+ QStringList files(QMakeProject *project) const;
+ inline bool isBuildable() const { return buildable; }
+ inline QString keyName() const { return key; }
+ inline QString groupName() const { return group; }
+ inline QString compilerName() const { return compiler; }
+ inline bool isObjectOutput(const QString &file) const {
+ bool ret = object_output;
+ for(int i = 0; !ret && i < Option::c_ext.size(); ++i) {
+ if(file.endsWith(Option::c_ext.at(i))) {
+ ret = true;
+ break;
+ }
+ }
+ for(int i = 0; !ret && i < Option::cpp_ext.size(); ++i) {
+ if(file.endsWith(Option::cpp_ext.at(i))) {
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+ }
+};
+
+ProjectBuilderSources::ProjectBuilderSources(const QString &k, bool b,
+ const QString &g, const QString &c, bool o) : buildable(b), object_output(o), key(k), group(g), compiler(c)
+{
+ if(group.isNull()) {
+ if(k == "SOURCES")
+ group = "Sources";
+ else if(k == "HEADERS")
+ group = "Headers";
+ else if(k == "QMAKE_INTERNAL_INCLUDED_FILES")
+ group = "Sources [qmake]";
+ else if(k == "GENERATED_SOURCES" || k == "GENERATED_FILES")
+ group = "Temporary Sources";
+ else
+ fprintf(stderr, "No group available for %s!\n", k.toLatin1().constData());
+ }
+}
+
+QStringList
+ProjectBuilderSources::files(QMakeProject *project) const
+{
+ QStringList ret = project->values(key);
+ if(key == "QMAKE_INTERNAL_INCLUDED_FILES") {
+ QString pfile = project->projectFile();
+ if(pfile != "(stdin)")
+ ret.prepend(pfile);
+ for(int i = 0; i < ret.size(); ++i) {
+ QStringList newret;
+ if(!ret.at(i).endsWith(Option::prf_ext))
+ newret.append(ret.at(i));
+ ret = newret;
+ }
+ }
+ if(key == "SOURCES" && project->first("TEMPLATE") == "app" && !project->isEmpty("ICON"))
+ ret.append(project->first("ICON"));
+ return ret;
+}
+
+
+bool
+ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
+{
+ QStringList tmp;
+ bool did_preprocess = false;
+
+ //HEADER
+ const int pbVersion = pbuilderVersion();
+ t << "// !$*UTF8*$!" << "\n"
+ << "{" << "\n"
+ << "\t" << writeSettings("archiveVersion", "1", SettingsNoQuote) << ";" << "\n"
+ << "\t" << "classes = {" << "\n" << "\t" << "};" << "\n"
+ << "\t" << writeSettings("objectVersion", QString::number(pbVersion), SettingsNoQuote) << ";" << "\n"
+ << "\t" << "objects = {" << endl;
+
+ //MAKE QMAKE equivelant
+ if(!project->isActiveConfig("no_autoqmake") && project->projectFile() != "(stdin)") {
+ QString mkfile = pbx_dir + Option::dir_sep + "qt_makeqmake.mak";
+ QFile mkf(mkfile);
+ if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ writingUnixMakefileGenerator = true;
+ debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
+ QTextStream mkt(&mkf);
+ writeHeader(mkt);
+ mkt << "QMAKE = " << var("QMAKE_QMAKE") << endl;
+ writeMakeQmake(mkt);
+ mkt.flush();
+ mkf.close();
+ writingUnixMakefileGenerator = false;
+ }
+ QString phase_key = keyFor("QMAKE_PBX_MAKEQMAKE_BUILDPHASE");
+ mkfile = fileFixify(mkfile, qmake_getpwd());
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
+ t << "\t\t" << phase_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("generatedFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Qt Qmake") << ";" << "\n"
+ << "\t\t\t" << writeSettings("neededFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";" << "\n"
+ << "\t\t\t" << writeSettings("shellScript", fixForOutput("make -C " + escapeFilePath(qmake_getpwd()) + " -f '" + escapeFilePath(mkfile) + "'")) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ //DUMP SOURCES
+ QMap<QString, QStringList> groups;
+ QList<ProjectBuilderSources> sources;
+ sources.append(ProjectBuilderSources("SOURCES", true));
+ sources.append(ProjectBuilderSources("GENERATED_SOURCES", true));
+ sources.append(ProjectBuilderSources("GENERATED_FILES"));
+ sources.append(ProjectBuilderSources("HEADERS"));
+ sources.append(ProjectBuilderSources("QMAKE_INTERNAL_INCLUDED_FILES"));
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = project->first((*it) + ".output");
+ if(project->isEmpty((*it) + ".output"))
+ continue;
+ QString name = (*it);
+ if(!project->isEmpty((*it) + ".name"))
+ name = project->first((*it) + ".name");
+ const QStringList &inputs = project->values((*it) + ".input");
+ for(int input = 0; input < inputs.size(); ++input) {
+ if(project->isEmpty(inputs.at(input)))
+ continue;
+ bool duplicate = false;
+ for(int i = 0; i < sources.size(); ++i) {
+ if(sources.at(i).keyName() == inputs.at(input)) {
+ duplicate = true;
+ break;
+ }
+ }
+ if(!duplicate) {
+ bool isObj = project->values((*it) + ".CONFIG").indexOf("no_link") == -1;
+ const QStringList &outputs = project->values((*it) + ".variable_out");
+ for(int output = 0; output < outputs.size(); ++output) {
+ if(outputs.at(output) != "OBJECT") {
+ isObj = false;
+ break;
+ }
+ }
+ sources.append(ProjectBuilderSources(inputs.at(input), true,
+ QString("Sources [") + name + "]", (*it), isObj));
+ }
+ }
+ }
+ }
+ for(int source = 0; source < sources.size(); ++source) {
+ QStringList &src_list = project->values("QMAKE_PBX_" + sources.at(source).keyName());
+ QStringList &root_group_list = project->values("QMAKE_PBX_GROUPS");
+
+ QStringList files = fileFixify(sources.at(source).files(project));
+ for(int f = 0; f < files.count(); ++f) {
+ QString file = files[f];
+ if(file.length() >= 2 && (file[0] == '"' || file[0] == '\'') && file[(int) file.length()-1] == file[0])
+ file = file.mid(1, file.length()-2);
+ if(!sources.at(source).compilerName().isNull() &&
+ !verifyExtraCompiler(sources.at(source).compilerName(), file))
+ continue;
+ if(file.endsWith(Option::prl_ext))
+ continue;
+
+ bool in_root = true;
+ QString src_key = keyFor(file), name = file;
+ if(project->isActiveConfig("flat")) {
+ QString flat_file = fileFixify(file, qmake_getpwd(), Option::output_dir, FileFixifyRelative);
+ if(flat_file.indexOf(Option::dir_sep) != -1) {
+ QStringList dirs = flat_file.split(Option::dir_sep);
+ name = dirs.back();
+ }
+ } else {
+ QString flat_file = fileFixify(file, qmake_getpwd(), Option::output_dir, FileFixifyRelative);
+ if(QDir::isRelativePath(flat_file) && flat_file.indexOf(Option::dir_sep) != -1) {
+ QString last_grp("QMAKE_PBX_" + sources.at(source).groupName() + "_HEIR_GROUP");
+ QStringList dirs = flat_file.split(Option::dir_sep);
+ name = dirs.back();
+ dirs.pop_back(); //remove the file portion as it will be added via src_key
+ for(QStringList::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
+ QString new_grp(last_grp + Option::dir_sep + (*dir_it)), new_grp_key(keyFor(new_grp));
+ if(dir_it == dirs.begin()) {
+ if(!src_list.contains(new_grp_key))
+ src_list.append(new_grp_key);
+ } else {
+ if(!groups[last_grp].contains(new_grp_key))
+ groups[last_grp] += new_grp_key;
+ }
+ last_grp = new_grp;
+ }
+ groups[last_grp] += src_key;
+ in_root = false;
+ }
+ }
+ if(in_root)
+ src_list.append(src_key);
+ //source reference
+ t << "\t\t" << src_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", escapeFilePath(file)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(file)), SettingsNoQuote) << ";" << "\n";
+ if(pbVersion >= 38) {
+ QString filetype;
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) {
+ if(file.endsWith((*cppit))) {
+ filetype = "sourcecode.cpp.cpp";
+ break;
+ }
+ }
+ if(!filetype.isNull())
+ t << "\t\t\t" << writeSettings("lastKnownFileType", filetype) << ";" << "\n";
+ }
+ t << "\t\t" << "};" << "\n";
+ if(sources.at(source).isBuildable()) { //build reference
+ QString build_key = keyFor(file + ".BUILDABLE");
+ t << "\t\t" << build_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("fileRef", src_key) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "settings = {" << "\n"
+ << "\t\t\t\t" << writeSettings("ATTRIBUTES", QStringList(), SettingsAsList, 5) << ";" << "\n"
+ << "\t\t\t" << "};" << "\n"
+ << "\t\t" << "};" << "\n";
+ if(sources.at(source).isObjectOutput(file))
+ project->values("QMAKE_PBX_OBJ").append(build_key);
+ }
+ }
+ if(!src_list.isEmpty()) {
+ QString group_key = keyFor(sources.at(source).groupName());
+ if(root_group_list.indexOf(group_key) == -1)
+ root_group_list += group_key;
+
+ QStringList &group = groups[sources.at(source).groupName()];
+ for(int src = 0; src < src_list.size(); ++src) {
+ if(group.indexOf(src_list.at(src)) == -1)
+ group += src_list.at(src);
+ }
+ }
+ }
+ for(QMap<QString, QStringList>::Iterator grp_it = groups.begin(); grp_it != groups.end(); ++grp_it) {
+ t << "\t\t" << keyFor(grp_it.key()) << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("children", grp_it.value(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(grp_it.key().section(Option::dir_sep, -1))) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ //PREPROCESS BUILDPHASE (just a makefile)
+ {
+ QString mkfile = pbx_dir + Option::dir_sep + "qt_preprocess.mak";
+ QFile mkf(mkfile);
+ if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ writingUnixMakefileGenerator = true;
+ did_preprocess = true;
+ debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
+ QTextStream mkt(&mkf);
+ writeHeader(mkt);
+ mkt << "MOC = " << Option::fixPathToTargetOS(var("QMAKE_MOC")) << endl;
+ mkt << "UIC = " << Option::fixPathToTargetOS(var("QMAKE_UIC")) << endl;
+ mkt << "LEX = " << var("QMAKE_LEX") << endl;
+ mkt << "LEXFLAGS = " << var("QMAKE_LEXFLAGS") << endl;
+ mkt << "YACC = " << var("QMAKE_YACC") << endl;
+ mkt << "YACCFLAGS = " << var("QMAKE_YACCFLAGS") << endl;
+ mkt << "DEFINES = "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << varGlue("DEFINES","-D"," -D","") << endl;
+ mkt << "INCPATH = " << "-I" << specdir();
+ if(!project->isActiveConfig("no_include_pwd")) {
+ QString pwd = escapeFilePath(fileFixify(qmake_getpwd()));
+ if(pwd.isEmpty())
+ pwd = ".";
+ mkt << " -I" << pwd;
+ }
+ {
+ const QStringList &incs = project->values("INCLUDEPATH");
+ for(QStringList::ConstIterator incit = incs.begin(); incit != incs.end(); ++incit)
+ mkt << " " << "-I" << escapeFilePath((*incit));
+ }
+ if(!project->isEmpty("QMAKE_FRAMEWORKPATH_FLAGS"))
+ mkt << " " << var("QMAKE_FRAMEWORKPATH_FLAGS");
+ mkt << endl;
+ mkt << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ mkt << "MOVE = " << var("QMAKE_MOVE") << endl << endl;
+ mkt << "IMAGES = " << varList("QMAKE_IMAGE_COLLECTION") << endl;
+ mkt << "PARSERS =";
+ if(!project->isEmpty("YACCSOURCES")) {
+ QStringList &yaccs = project->values("YACCSOURCES");
+ for(QStringList::Iterator yit = yaccs.begin(); yit != yaccs.end(); ++yit) {
+ QFileInfo fi(fileInfo((*yit)));
+ mkt << " " << fi.path() << Option::dir_sep << fi.baseName()
+ << Option::yacc_mod << Option::cpp_ext.first();
+ }
+ }
+ if(!project->isEmpty("LEXSOURCES")) {
+ QStringList &lexs = project->values("LEXSOURCES");
+ for(QStringList::Iterator lit = lexs.begin(); lit != lexs.end(); ++lit) {
+ QFileInfo fi(fileInfo((*lit)));
+ mkt << " " << fi.path() << Option::dir_sep << fi.baseName()
+ << Option::lex_mod << Option::cpp_ext.first();
+ }
+ }
+ mkt << "\n";
+ mkt << "preprocess: $(PARSERS) compilers" << endl;
+ mkt << "clean preprocess_clean: parser_clean compiler_clean" << endl << endl;
+ mkt << "parser_clean:" << "\n";
+ if(!project->isEmpty("YACCSOURCES") || !project->isEmpty("LEXSOURCES"))
+ mkt << "\t-rm -f $(PARSERS)" << "\n";
+ writeExtraTargets(mkt);
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ mkt << "compilers:";
+ const QStringList &compilers = project->values("QMAKE_EXTRA_COMPILERS");
+ for(int compiler = 0; compiler < compilers.size(); ++compiler) {
+ QString tmp_out = project->first(compilers.at(compiler) + ".output");
+ if(project->isEmpty(compilers.at(compiler) + ".output"))
+ continue;
+ const QStringList &inputs = project->values(compilers.at(compiler) + ".input");
+ for(int input = 0; input < inputs.size(); ++input) {
+ if(project->isEmpty(inputs.at(input)))
+ continue;
+ const QStringList &files = project->values(inputs.at(input));
+ for(int file = 0, added = 0; file < files.size(); ++file) {
+ if(!verifyExtraCompiler(compilers.at(compiler), files.at(file)))
+ continue;
+ if(added && !(added % 3))
+ mkt << "\\\n\t";
+ ++added;
+ const QString file_name = fileFixify(files.at(file), Option::output_dir, Option::output_dir);
+ mkt << " " << replaceExtraCompilerVariables(tmp_out, file_name, QString());
+ }
+ }
+ }
+ mkt << endl;
+ writeExtraCompilerTargets(mkt);
+ writingUnixMakefileGenerator = false;
+ }
+ mkt.flush();
+ mkf.close();
+ }
+ mkfile = fileFixify(mkfile, qmake_getpwd());
+ QString phase_key = keyFor("QMAKE_PBX_PREPROCESS_TARGET");
+// project->values("QMAKE_PBX_BUILDPHASES").append(phase_key);
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
+ t << "\t\t" << phase_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("generatedFileNames", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Qt Preprocessors") << ";" << "\n"
+ << "\t\t\t" << writeSettings("neededFileNames", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";" << "\n"
+ << "\t\t\t" << writeSettings("shellScript", fixForOutput("make -C " + escapeFilePath(qmake_getpwd()) + " -f '" + escapeFilePath(mkfile) + "'")) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ //SOURCE BUILDPHASE
+ if(!project->isEmpty("QMAKE_PBX_OBJ")) {
+ QString grp = "Build Sources", key = keyFor(grp);
+ project->values("QMAKE_PBX_BUILDPHASES").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXSourcesBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", grp) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ if(!project->isActiveConfig("staticlib")) { //DUMP LIBRARIES
+ QStringList &libdirs = project->values("QMAKE_PBX_LIBPATHS"),
+ &frameworkdirs = project->values("QMAKE_FRAMEWORKPATH");
+ QString libs[] = { "QMAKE_LFLAGS", "QMAKE_LIBDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS",
+ "QMAKE_LIBS", QString() };
+ for(int i = 0; !libs[i].isNull(); i++) {
+ tmp = project->values(libs[i]);
+ for(int x = 0; x < tmp.count();) {
+ bool remove = false;
+ QString library, name, opt = tmp[x].trimmed();
+ if(opt.length() >= 2 && (opt[0] == '"' || opt[0] == '\'') &&
+ opt[(int) opt.length()-1] == opt[0])
+ opt = opt.mid(1, opt.length()-2);
+ if(opt.startsWith("-L")) {
+ QString r = opt.right(opt.length() - 2);
+ fixForOutput(r);
+ libdirs.append(r);
+ } else if(opt == "-prebind") {
+ project->values("QMAKE_DO_PREBINDING").append("TRUE");
+ remove = true;
+ } else if(opt.startsWith("-l")) {
+ name = opt.right(opt.length() - 2);
+ QString lib("lib" + name);
+ for(QStringList::Iterator lit = libdirs.begin(); lit != libdirs.end(); ++lit) {
+ if(project->isActiveConfig("link_prl")) {
+ /* This isn't real nice, but it is real useful. This looks in a prl
+ for what the library will ultimately be called so we can stick it
+ in the ProjectFile. If the prl format ever changes (not likely) then
+ this will not really work. However, more concerning is that it will
+ encode the version number in the Project file which might be a bad
+ things in days to come? --Sam
+ */
+ QString lib_file = (*lit) + Option::dir_sep + lib;
+ if(QMakeMetaInfo::libExists(lib_file)) {
+ QMakeMetaInfo libinfo;
+ if(libinfo.readLib(lib_file)) {
+ if(!libinfo.isEmpty("QMAKE_PRL_TARGET")) {
+ library = (*lit) + Option::dir_sep + libinfo.first("QMAKE_PRL_TARGET");
+ debug_msg(1, "pbuilder: Found library (%s) via PRL %s (%s)",
+ opt.toLatin1().constData(), lib_file.toLatin1().constData(), library.toLatin1().constData());
+ remove = true;
+ }
+ }
+ }
+ }
+ if(!remove) {
+ QString extns[] = { ".dylib", ".so", ".a", QString() };
+ for(int n = 0; !remove && !extns[n].isNull(); n++) {
+ QString tmp = (*lit) + Option::dir_sep + lib + extns[n];
+ if(exists(tmp)) {
+ library = tmp;
+ debug_msg(1, "pbuilder: Found library (%s) via %s",
+ opt.toLatin1().constData(), library.toLatin1().constData());
+ remove = true;
+ }
+ }
+ }
+ }
+ } else if(opt.startsWith("-F")) {
+ QString r;
+ if(opt.size() > 2) {
+ r = opt.right(opt.length() - 2);
+ } else {
+ if(x == tmp.count()-1)
+ break;
+ r = tmp[++x];
+ }
+ if(!r.isEmpty()) {
+ fixForOutput(r);
+ frameworkdirs.append(r);
+ }
+ } else if(opt == "-framework") {
+ if(x == tmp.count()-1)
+ break;
+ const QString framework = tmp[x+1];
+ QStringList fdirs = frameworkdirs;
+ fdirs << "/System/Library/Frameworks/" << "/Library/Frameworks/";
+ for(int fdir = 0; fdir < fdirs.count(); fdir++) {
+ if(exists(fdirs[fdir] + QDir::separator() + framework + ".framework")) {
+ tmp.removeAt(x);
+ remove = true;
+ library = fdirs[fdir] + Option::dir_sep + framework + ".framework";
+ break;
+ }
+ }
+ } else if(opt.left(1) != "-") {
+ if(exists(opt)) {
+ remove = true;
+ library = opt;
+ }
+ }
+ if(!library.isEmpty()) {
+ const int slsh = library.lastIndexOf(Option::dir_sep);
+ if(name.isEmpty()) {
+ if(slsh != -1)
+ name = library.right(library.length() - slsh - 1);
+ }
+ if(slsh != -1) {
+ const QString path = QFileInfo(library.left(slsh)).absoluteFilePath();
+ if(!path.isEmpty() && !libdirs.contains(path))
+ libdirs += path;
+ }
+ library = fileFixify(library);
+ QString key = keyFor(library);
+ bool is_frmwrk = (library.endsWith(".framework"));
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", (is_frmwrk ? "PBXFrameworkReference" : "PBXFileReference"), SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", escapeFilePath(library)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(library)), SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ project->values("QMAKE_PBX_LIBRARIES").append(key);
+ QString build_key = keyFor(library + ".BUILDABLE");
+ t << "\t\t" << build_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("fileRef", key) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "settings = {" << "\n"
+ << "\t\t\t" << "};" << "\n"
+ << "\t\t" << "};" << "\n";
+ project->values("QMAKE_PBX_BUILD_LIBRARIES").append(build_key);
+ }
+ if(remove)
+ tmp.removeAt(x);
+ else
+ x++;
+ }
+ project->values(libs[i]) = tmp;
+ }
+ }
+ //SUBLIBS BUILDPHASE (just another makefile)
+ if(!project->isEmpty("SUBLIBS")) {
+ QString mkfile = pbx_dir + Option::dir_sep + "qt_sublibs.mak";
+ QFile mkf(mkfile);
+ if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ writingUnixMakefileGenerator = true;
+ debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
+ QTextStream mkt(&mkf);
+ writeHeader(mkt);
+ mkt << "SUBLIBS= ";
+ tmp = project->values("SUBLIBS");
+ for(int i = 0; i < tmp.count(); i++)
+ t << "tmp/lib" << tmp[i] << ".a ";
+ t << endl << endl;
+ mkt << "sublibs: $(SUBLIBS)" << endl << endl;
+ tmp = project->values("SUBLIBS");
+ for(int i = 0; i < tmp.count(); i++)
+ t << "tmp/lib" << tmp[i] << ".a" << ":\n\t"
+ << var(QString("MAKELIB") + tmp[i]) << endl << endl;
+ mkt.flush();
+ mkf.close();
+ writingUnixMakefileGenerator = false;
+ }
+ QString phase_key = keyFor("QMAKE_PBX_SUBLIBS_BUILDPHASE");
+ mkfile = fileFixify(mkfile, qmake_getpwd());
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
+ t << "\t\t" << phase_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("generatedFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Qt Sublibs") << ";" << "\n"
+ << "\t\t\t" << writeSettings("neededFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << "\n"
+ << "\t\t\t" << writeSettings("shellScript", fixForOutput("make -C " + escapeFilePath(qmake_getpwd()) + " -f '" + escapeFilePath(mkfile) + "'")) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ //LIBRARY BUILDPHASE
+ if(!project->isEmpty("QMAKE_PBX_LIBRARIES")) {
+ tmp = project->values("QMAKE_PBX_LIBRARIES");
+ if(!tmp.isEmpty()) {
+ QString grp("External Frameworks and Libraries"), key = keyFor(grp);
+ project->values("QMAKE_PBX_GROUPS").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_LIBRARIES"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", QStringList()) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ }
+ {
+ QString grp("Frameworks & Libraries"), key = keyFor(grp);
+ project->values("QMAKE_PBX_BUILDPHASES").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", project->values("QMAKE_PBX_BUILD_LIBRARIES"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFrameworksBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ if(project->isActiveConfig("app_bundle") && project->first("TEMPLATE") == "app") { //BUNDLE RESOURCES
+ QString grp("Bundle Resources"), key = keyFor(grp);
+ project->values("QMAKE_PBX_BUILDPHASES").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "files = (" << "\n";
+ if(!project->isEmpty("ICON")) {
+ QString icon = project->first("ICON");
+ if(icon.length() >= 2 && (icon[0] == '"' || icon[0] == '\'') && icon[(int)icon.length()-1] == icon[0])
+ icon = icon.mid(1, icon.length()-2);
+ t << "\t\t\t\t" << keyFor(icon + ".BUILDABLE") << ",\n";
+ }
+ t << "\t\t\t" << ");" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXResourcesBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ { //INSTALL BUILDPHASE (copy)
+ QString phase_key = keyFor("QMAKE_PBX_TARGET_COPY_PHASE");
+ QString destDir = Option::output_dir;
+ if (!project->isEmpty("QMAKE_ORIG_DESTDIR"))
+ destDir = project->first("QMAKE_ORIG_DESTDIR");
+ destDir = fixForOutput(destDir);
+ destDir = fileInfo(Option::fixPathToLocalOS(destDir)).absoluteFilePath();
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
+ t << "\t\t" << phase_key << " = {\n"
+ << "\t\t\t" << writeSettings("name", "Project Copy") << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("dstPath", escapeFilePath(destDir)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("dstSubfolderSpec", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", keyFor("QMAKE_PBX_TARGET_COPY_FILE"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};\n"
+ << "\t\t" << keyFor("QMAKE_PBX_TARGET_COPY_FILE") << " = {\n"
+ << "\t\t\t" << writeSettings("fileRef", keyFor(pbx_dir + "QMAKE_PBX_REFERENCE")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "settings = {\n"
+ << "\t\t\t" << "};\n"
+ << "\t\t" << "};\n";
+ }
+ //BUNDLE_DATA BUILDPHASE (copy)
+ if(!project->isEmpty("QMAKE_BUNDLE_DATA")) {
+ QStringList bundle_file_refs;
+ //all bundle data
+ const QStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA");
+ for(int i = 0; i < bundle_data.count(); i++) {
+ QStringList pbx_files;
+ //all files
+ const QStringList &files = project->values(bundle_data[i] + ".files");
+ for(int file = 0; file < files.count(); file++) {
+ QString file_ref_key = keyFor("QMAKE_PBX_BUNDLE_COPY_FILE_REF." + bundle_data[i] + "-" + files[file]);
+ bundle_file_refs += file_ref_key;
+ t << "\t\t" << file_ref_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", escapeFilePath(files[file])) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(files[file])), SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ QString copy_file_key = keyFor("QMAKE_PBX_BUNDLE_COPY_FILE." + bundle_data[i] + "-" + files[file]);
+ pbx_files += copy_file_key;
+ t << "\t\t" << copy_file_key << " = {\n"
+ << "\t\t\t" << writeSettings("fileRef", file_ref_key) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "settings = {\n"
+ << "\t\t\t" << "}" << ";" << "\n"
+ << "\t\t" << "}" << ";" << "\n";
+ }
+ //the phase
+ QString phase_key = keyFor("QMAKE_PBX_BUNDLE_COPY." + bundle_data[i]);
+ QString path;
+ if(!project->isEmpty(bundle_data[i] + ".version")) {
+ //###
+ }
+ path += project->first(bundle_data[i] + ".path");
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
+ t << "\t\t" << phase_key << " = {\n"
+ << "\t\t\t" << writeSettings("name", "Bundle Copy [" + bundle_data[i] + "]") << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("dstPath", escapeFilePath(path)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("dstSubfolderSpec", "1", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", pbx_files, SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "}" << ";" << "\n";
+ }
+ QString bundle_copy_key = keyFor("QMAKE_PBX_BUNDLE_COPY");
+ project->values("QMAKE_PBX_GROUPS").append(bundle_copy_key);
+ t << "\t\t" << bundle_copy_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", bundle_file_refs, SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Source [bundle data]") << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", QStringList()) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ if(/*pbVersion >= 38 &&*/ !project->isEmpty("QMAKE_PBX_PRESCRIPT_BUILDPHASES") && 0) {
+ // build reference
+ t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPT_BUILDREFERENCE") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("includeInIndex", "0") << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", "preprocessor.out") << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ project->values("QMAKE_PBX_PRODUCTS").append(keyFor("QMAKE_PBX_PRESCRIPTS_BUILDREFERENCE"));
+ //build phase
+ t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPTS_BUILDPHASE") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildPhases", project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildRules", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildSettings", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("dependencies", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXNativeTarget", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Qt Preprocessor Steps") << ";" << "\n"
+ << "\t\t\t" << writeSettings("productName", "Qt Preprocessor Steps") << ";" << "\n"
+ << "\t\t\t" << writeSettings("productReference", keyFor("QMAKE_PBX_PRESCRIPTS_BUILDREFERENCE")) << ";" << "\n";
+ if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
+ t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
+ else
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.tool") << ";" << "\n";
+ t << "\t\t" << "};" << "\n";
+ //dependency
+ t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPTS_DEPENDENCY") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXTargetDependency", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("target", keyFor("QMAKE_PBX_PRESCRIPTS_BUILDPHASE")) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ project->values("QMAKE_PBX_TARGET_DEPENDS").append(keyFor("QMAKE_PBX_PRESCRIPTS_DEPENDENCY"));
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").clear(); //these are already consumed above
+ }
+
+ //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER
+ //ROOT_GROUP
+ t << "\t\t" << keyFor("QMAKE_PBX_ROOT_GROUP") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_GROUPS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", QStringList()) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ //REFERENCE
+ project->values("QMAKE_PBX_PRODUCTS").append(keyFor(pbx_dir + "QMAKE_PBX_REFERENCE"));
+ t << "\t\t" << keyFor(pbx_dir + "QMAKE_PBX_REFERENCE") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n";
+ if(project->first("TEMPLATE") == "app") {
+ QString targ = project->first("QMAKE_ORIG_TARGET");
+ if(project->isActiveConfig("bundle") && !project->isEmpty("QMAKE_BUNDLE_EXTENSION")) {
+ if(!project->isEmpty("QMAKE_BUNDLE_NAME"))
+ targ = project->first("QMAKE_BUNDLE_NAME");
+ targ += project->first("QMAKE_BUNDLE_EXTENSION");
+ if(!project->isEmpty("QMAKE_PBX_BUNDLE_TYPE"))
+ t << "\t\t\t" << writeSettings("explicitFileType", project->first("QMAKE_PBX_BUNDLE_TYPE")) + ";" << "\n";
+ } else if(project->isActiveConfig("app_bundle")) {
+ if(!project->isEmpty("QMAKE_APPLICATION_BUNDLE_NAME"))
+ targ = project->first("QMAKE_APPLICATION_BUNDLE_NAME");
+ targ += ".app";
+ t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.application") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.executable") << ";" << "\n";
+ }
+ QString app = (!project->isEmpty("DESTDIR") ? project->first("DESTDIR") + project->first("QMAKE_ORIG_TARGET") :
+ qmake_getpwd()) + Option::dir_sep + targ;
+ t << "\t\t\t" << writeSettings("path", escapeFilePath(targ)) << ";" << "\n";
+ } else {
+ QString lib = project->first("QMAKE_ORIG_TARGET");
+ if(project->isActiveConfig("staticlib")) {
+ lib = project->first("TARGET");
+ } else if(!project->isActiveConfig("lib_bundle")) {
+ if(project->isActiveConfig("plugin"))
+ lib = project->first("TARGET");
+ else
+ lib = project->first("TARGET_");
+ }
+ int slsh = lib.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ lib = lib.right(lib.length() - slsh - 1);
+ if(project->isActiveConfig("bundle") && !project->isEmpty("QMAKE_BUNDLE_EXTENSION")) {
+ if(!project->isEmpty("QMAKE_BUNDLE_NAME"))
+ lib = project->first("QMAKE_BUNDLE_NAME");
+ lib += project->first("QMAKE_BUNDLE_EXTENSION");
+ if(!project->isEmpty("QMAKE_PBX_BUNDLE_TYPE"))
+ t << "\t\t\t" << writeSettings("explicitFileType", project->first("QMAKE_PBX_BUNDLE_TYPE")) << ";" << "\n";
+ } else if(!project->isActiveConfig("staticlib") && project->isActiveConfig("lib_bundle")) {
+ if(!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME"))
+ lib = project->first("QMAKE_FRAMEWORK_BUNDLE_NAME");
+ lib += ".framework";
+ t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.framework") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("explicitFileType", "compiled.mach-o.dylib") << ";" << "\n";
+ }
+ t << "\t\t\t" << writeSettings("path", escapeFilePath(lib)) << ";" << "\n";
+ }
+ t << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ { //Products group
+ QString grp("Products"), key = keyFor(grp);
+ project->values("QMAKE_PBX_GROUPS").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_PRODUCTS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Products") << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ //TARGET
+ QString target_key = keyFor(pbx_dir + "QMAKE_PBX_TARGET");
+ project->values("QMAKE_PBX_TARGETS").append(target_key);
+ t << "\t\t" << target_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildPhases", project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES") + project->values("QMAKE_PBX_BUILDPHASES"),
+ SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n";
+ QString cCompiler = project->first("QMAKE_CC");
+ if (!cCompiler.isEmpty()) {
+ t << "\t\t\t\t" << writeSettings("CC", fixForOutput(findProgram(cCompiler))) << ";" << "\n";
+ }
+ cCompiler = project->first("QMAKE_CXX");
+ if (!cCompiler.isEmpty()) {
+ t << "\t\t\t\t" << writeSettings("CPLUSPLUS", fixForOutput(findProgram(cCompiler))) << ";" << "\n";
+ }
+
+ t << "\t\t\t\t" << writeSettings("HEADER_SEARCH_PATHS", fixListForOutput("INCLUDEPATH") + QStringList(fixForOutput(specdir())), SettingsAsList, 5) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("LIBRARY_SEARCH_PATHS", fixListForOutput("QMAKE_PBX_LIBPATHS"), SettingsAsList, 5) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("OPTIMIZATION_CFLAGS", QStringList(), SettingsAsList, 5) << ";" << "\n";
+ {
+ QStringList cflags = fixListForOutput("QMAKE_CFLAGS");
+ const QStringList &prl_defines = project->values("PRL_EXPORT_DEFINES");
+ for(int i = 0; i < prl_defines.size(); ++i)
+ cflags += "-D" + prl_defines.at(i);
+ const QStringList &defines = project->values("DEFINES");
+ for(int i = 0; i < defines.size(); ++i)
+ cflags += "-D" + defines.at(i);
+ t << "\t\t\t\t" << writeSettings("OTHER_CFLAGS", cflags, SettingsAsList, 5) << ";" << "\n";
+ }
+ {
+ QStringList cxxflags = fixListForOutput("QMAKE_CXXFLAGS");
+ const QStringList &prl_defines = project->values("PRL_EXPORT_DEFINES");
+ for(int i = 0; i < prl_defines.size(); ++i)
+ cxxflags += "-D" + prl_defines.at(i);
+ const QStringList &defines = project->values("DEFINES");
+ for(int i = 0; i < defines.size(); ++i)
+ cxxflags += "-D" + defines.at(i);
+ t << "\t\t\t\t" << writeSettings("OTHER_CPLUSPLUSFLAGS", cxxflags, SettingsAsList, 5) << ";" << "\n";
+ }
+ t << "\t\t\t\t" << writeSettings("LEXFLAGS", fixListForOutput("QMAKE_LEXFLAGS")) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("YACCFLAGS", fixListForOutput("QMAKE_YACCFLAGS")) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("OTHER_REZFLAGS", QStringList()) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("SECTORDER_FLAGS", QStringList()) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("WARNING_CFLAGS", QStringList()) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("PREBINDING", QStringList((project->isEmpty("QMAKE_DO_PREBINDING") ? "NO" : "YES")), SettingsNoQuote) << ";" << "\n";
+ if(!project->isEmpty("PRECOMPILED_HEADER")) {
+ if(pbVersion >= 38) {
+ t << "\t\t\t\t" << writeSettings("GCC_PRECOMPILE_PREFIX_HEADER", "YES") << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("GCC_PREFIX_HEADER", escapeFilePath(project->first("PRECOMPILED_HEADER"))) << ";" << "\n";
+ } else {
+ t << "\t\t\t\t" << writeSettings("PRECOMPILE_PREFIX_HEADER", "YES") << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("PREFIX_HEADER", escapeFilePath(project->first("PRECOMPILED_HEADER"))) << ";" << "\n";
+ }
+ }
+ if((project->first("TEMPLATE") == "app" && project->isActiveConfig("app_bundle")) ||
+ (project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") &&
+ project->isActiveConfig("lib_bundle"))) {
+ QString plist = fileFixify(project->first("QMAKE_INFO_PLIST"));
+ if(plist.isEmpty())
+ plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE");
+ if(exists(plist)) {
+ QFile plist_in_file(plist);
+ if(plist_in_file.open(QIODevice::ReadOnly)) {
+ QTextStream plist_in(&plist_in_file);
+ QString plist_in_text = plist_in.readAll();
+ plist_in_text = plist_in_text.replace("@ICON@",
+ (project->isEmpty("ICON") ? QString("") : project->first("ICON").section(Option::dir_sep, -1)));
+ if(project->first("TEMPLATE") == "app") {
+ plist_in_text = plist_in_text.replace("@EXECUTABLE@", project->first("QMAKE_ORIG_TARGET"));
+ } else {
+ plist_in_text = plist_in_text.replace("@LIBRARY@", project->first("QMAKE_ORIG_TARGET"));
+ }
+ if (!project->values("VERSION").isEmpty()) {
+ plist_in_text = plist_in_text.replace("@SHORT_VERSION@", project->first("VER_MAJ") + "." +
+ project->first("VER_MIN"));
+ }
+ 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");
+ 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";
+ }
+ }
+ }
+ }
+#if 1
+ t << "\t\t\t\t" << writeSettings("BUILD_ROOT", escapeFilePath(qmake_getpwd())) << ";" << "\n";
+#endif
+ if(!project->isActiveConfig("staticlib")) {
+ t << "\t\t\t\t" << writeSettings("OTHER_LDFLAGS",
+ fixListForOutput("SUBLIBS")
+ + fixListForOutput("QMAKE_LFLAGS")
+ + fixListForOutput("QMAKE_LIBDIR_FLAGS")
+ + fixListForOutput("QMAKE_FRAMEWORKPATH_FLAGS")
+ + fixListForOutput("QMAKE_LIBS"),
+ SettingsAsList, 6) << ";" << "\n";
+ }
+ if(!project->isEmpty("DESTDIR")) {
+ QString dir = project->first("DESTDIR");
+ if (QDir::isRelativePath(dir))
+ dir.prepend(qmake_getpwd() + Option::dir_sep);
+ t << "\t\t\t\t" << writeSettings("INSTALL_DIR", dir) << ";" << "\n";
+ }
+ if (project->first("TEMPLATE") == "lib") {
+ t << "\t\t\t\t" << writeSettings("INSTALL_PATH", QStringList()) << ";" << "\n";
+ }
+ if(!project->isEmpty("VERSION") && project->first("VERSION") != "0.0.0") {
+ t << "\t\t\t\t" << writeSettings("DYLIB_CURRENT_VERSION", project->first("VER_MAJ")+"."+project->first("VER_MIN")+"."+project->first("VER_PAT")) << ";" << "\n";
+ if(project->isEmpty("COMPAT_VERSION"))
+ t << "\t\t\t\t" << writeSettings("DYLIB_COMPATIBILITY_VERSION", project->first("VER_MAJ")+"."+project->first("VER_MIN")) << ";" << "\n";
+ if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") &&
+ project->isActiveConfig("lib_bundle"))
+ t << "\t\t\t\t" << writeSettings("FRAMEWORK_VERSION", project->first("QMAKE_FRAMEWORK_VERSION")) << ";" << "\n";
+ }
+ if(!project->isEmpty("COMPAT_FRAMEWORKPATH"))
+ t << "\t\t\t\t" << writeSettings("FRAMEWORK_SEARCH_PATHS", fixListForOutput("QMAKE_FRAMEWORKPATH"), SettingsAsList, 5) << ";" << "\n";
+ if(!project->isEmpty("COMPAT_VERSION"))
+ t << "\t\t\t\t" << writeSettings("DYLIB_COMPATIBILITY_VERSION", project->first("COMPAT_VERSION")) << ";" << "\n";
+ if(!project->isEmpty("QMAKE_MACOSX_DEPLOYMENT_TARGET"))
+ t << "\t\t\t\t" << writeSettings("MACOSX_DEPLOYMENT_TARGET", project->first("QMAKE_MACOSX_DEPLOYMENT_TARGET")) << ";" << "\n";
+ if(pbVersion >= 38) {
+ if(!project->isEmpty("OBJECTS_DIR"))
+ t << "\t\t\t\t" << writeSettings("OBJROOT", fixForOutput(project->first("OBJECTS_DIR"))) << ";" << "\n";
+ }
+#if 0
+ if(!project->isEmpty("DESTDIR"))
+ t << "\t\t\t\t" << writeSettings("SYMROOT", fixForOutput(project->first("DESTDIR"))) << ";" << "\n";
+ else
+ t << "\t\t\t\t" << writeSettings("SYMROOT", fixForOutput(qmake_getpwd())) << ";" << "\n";
+#endif
+ {
+ QStringList archs;
+ if(project->isActiveConfig("x86"))
+ archs += "i386";
+ if(project->isActiveConfig("ppc")) {
+ if(!archs.isEmpty())
+ archs += " ";
+ archs += "ppc";
+ }
+ if(project->isActiveConfig("ppc64")) {
+ if(!archs.isEmpty())
+ archs += " ";
+ archs += "ppc64";
+ }
+ if(project->isActiveConfig("x86_64")) {
+ if(!archs.isEmpty())
+ archs += " ";
+ archs += "x86_64";
+ }
+ if(!archs.isEmpty())
+ t << "\t\t\t\t" << writeSettings("ARCHS", archs) << ";" << "\n";
+
+ }
+ if(project->first("TEMPLATE") == "app") {
+ if(pbVersion < 38 && project->isActiveConfig("app_bundle"))
+ t << "\t\t\t\t" << writeSettings("WRAPPER_SUFFIX", "app") << ";" << "\n";
+ t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", fixForOutput(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n";
+ } else {
+ if(!project->isActiveConfig("plugin") && project->isActiveConfig("staticlib")) {
+ t << "\t\t\t\t" << writeSettings("LIBRARY_STYLE", "STATIC") << ";" << "\n";
+ } else {
+ t << "\t\t\t\t" << writeSettings("LIBRARY_STYLE", "DYNAMIC") << ";" << "\n";
+ }
+ QString lib = project->first("QMAKE_ORIG_TARGET");
+ if(!project->isActiveConfig("lib_bundle") && !project->isActiveConfig("staticlib"))
+ lib.prepend("lib");
+ t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", escapeFilePath(lib)) << ";" << "\n";
+ }
+ tmp = project->values("QMAKE_PBX_VARS");
+ for(int i = 0; i < tmp.count(); i++) {
+ QString var = tmp[i], val = qgetenv(var.toLatin1());
+ if(val.isEmpty() && var == "TB")
+ val = "/usr/bin/";
+ t << "\t\t\t\t" << writeSettings(var, escapeFilePath(val)) << ";" << "\n";
+ }
+ t << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << "conditionalBuildSettings = {" << "\n"
+ << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("dependencies", project->values("QMAKE_PBX_TARGET_DEPENDS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("productReference", keyFor(pbx_dir + "QMAKE_PBX_REFERENCE")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("shouldUseHeadermap", "1", SettingsNoQuote) << ";" << "\n";
+ if(pbVersion >= 38)
+ t << "\t\t\t" << writeSettings("isa", "PBXNativeTarget", SettingsNoQuote) << ";" << "\n";
+ if(project->first("TEMPLATE") == "app") {
+ if(!project->isActiveConfig("app_bundle")) {
+ if(pbVersion >= 38) {
+ if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
+ t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
+ else
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.tool") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("isa", "PBXToolTarget", SettingsNoQuote) << ";" << "\n";
+ }
+ } else {
+ if(pbVersion >= 38) {
+ if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
+ t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
+ else
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.application") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("isa", "PBXApplicationTarget", SettingsNoQuote) << ";" << "\n";
+ }
+ t << "\t\t\t" << "productSettingsXML = \"";
+ bool read_plist = false;
+ if(exists("Info.plist")) {
+ QFile plist("Info.plist");
+ if (plist.open(QIODevice::ReadOnly)) {
+ read_plist = true;
+ QTextStream stream(&plist);
+ while(!stream.atEnd())
+ t << stream.readLine().replace('"', "\\\"") << endl;
+ }
+ }
+ if(!read_plist) {
+ t << "<?xml version="
+ << "\\\"1.0\\\" encoding=" << "\\\"UTF-8\\\"" << "?>" << "\n"
+ << "\t\t\t\t" << "<!DOCTYPE plist SYSTEM \\\"file://localhost/System/"
+ << "Library/DTDs/PropertyList.dtd\\\">" << "\n"
+ << "\t\t\t\t" << "<plist version=\\\"0.9\\\">" << "\n"
+ << "\t\t\t\t" << "<dict>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleDevelopmentRegion</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>English</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleExecutable</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>" << project->first("QMAKE_ORIG_TARGET") << "</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleIconFile</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>" << var("ICON").section(Option::dir_sep, -1) << "</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleInfoDictionaryVersion</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>6.0</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundlePackageType</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>APPL</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleSignature</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>"
+ << (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") :
+ project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << "</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleVersion</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>0.1</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CSResourcesFileMapped</key>" << "\n"
+ << "\t\t\t\t\t" << "<true/>" << "\n"
+ << "\t\t\t\t" << "</dict>" << "\n"
+ << "\t\t\t\t" << "</plist>";
+ }
+ t << "\";" << "\n";
+ }
+ t << "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n"
+ << "\t\t\t" << writeSettings("productName", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n";
+ } else {
+ QString lib = project->first("QMAKE_ORIG_TARGET");
+ if(!project->isActiveConfig("lib_bundle") && !project->isActiveConfig("staticlib"))
+ lib.prepend("lib");
+ t << "\t\t\t" << writeSettings("name", escapeFilePath(lib)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("productName", escapeFilePath(lib)) << ";" << "\n";
+ if(pbVersion >= 38) {
+ if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
+ t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
+ else if(project->isActiveConfig("staticlib"))
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.library.static") << ";" << "\n";
+ else if(project->isActiveConfig("lib_bundle"))
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.framework") << ";" << "\n";
+ else
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.library.dynamic") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("isa", "PBXLibraryTarget", SettingsNoQuote) << ";" << "\n";
+ }
+ }
+ t << "\t\t\t" << writeSettings("startupPath", "<<ProjectDirectory>>") << ";" << "\n";
+ if(!project->isEmpty("DESTDIR"))
+ t << "\t\t\t" << writeSettings("productInstallPath", escapeFilePath(project->first("DESTDIR"))) << ";" << "\n";
+ t << "\t\t" << "};" << "\n";
+ //DEBUG/RELEASE
+ QString active_buildstyle;
+ for(int as_release = 0; as_release < 2; as_release++)
+ {
+ QMap<QString, QString> settings;
+ settings.insert("COPY_PHASE_STRIP", (as_release ? "YES" : "NO"));
+ settings.insert("GCC_GENERATE_DEBUGGING_SYMBOLS", as_release ? "NO" : "YES");
+ if(!as_release)
+ settings.insert("GCC_OPTIMIZATION_LEVEL", "0");
+ if(project->isActiveConfig("sdk") && !project->isEmpty("QMAKE_MAC_SDK"))
+ settings.insert("SDKROOT", project->first("QMAKE_MAC_SDK"));
+ {
+ const QStringList &l = project->values("QMAKE_MAC_XCODE_SETTINGS");
+ for(int i = 0; i < l.size(); ++i) {
+ QString name = l.at(i);
+ const QString value = project->values(name + QLatin1String(".value")).join(QString(Option::field_sep));
+ if(!project->isEmpty(name + QLatin1String(".name")))
+ name = project->values(name + QLatin1String(".name")).first();
+ settings.insert(name, value);
+ }
+ }
+
+ QString name;
+ if(pbVersion >= 42)
+ name = (as_release ? "Release" : "Debug");
+ else
+ name = (as_release ? "Deployment" : "Development");
+ if(pbVersion >= 42) {
+ QString key = keyFor("QMAKE_PBX_BUILDCONFIG_" + name);
+ project->values("QMAKE_PBX_BUILDCONFIGS").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "XCBuildConfiguration", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n";
+ for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
+ t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";\n";
+ t << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ QString key = keyFor("QMAKE_PBX_BUILDSTYLE_" + name);
+ if(project->isActiveConfig("debug") != (bool)as_release) {
+ project->values("QMAKE_PBX_BUILDSTYLES").append(key);
+ active_buildstyle = name;
+ } else if(pbVersion >= 42) {
+ project->values("QMAKE_PBX_BUILDSTYLES").append(key);
+ }
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildRules", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n";
+ for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
+ t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";" << "\n";
+ t << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildStyle") << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ if(pbVersion >= 42) {
+ t << "\t\t" << keyFor("QMAKE_PBX_BUILDCONFIG_LIST") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "XCConfigurationList", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildConfigurations", project->values("QMAKE_PBX_BUILDCONFIGS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("defaultConfigurationIsVisible", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("defaultConfigurationIsName", active_buildstyle) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ //ROOT
+ t << "\t\t" << keyFor("QMAKE_PBX_ROOT") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildStyles", project->values("QMAKE_PBX_BUILDSTYLES"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("hasScannedForEncodings", "1", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXProject", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("mainGroup", keyFor("QMAKE_PBX_ROOT_GROUP")) << ";" << "\n";
+ if(pbVersion >= 42)
+ t << "\t\t\t" << writeSettings("buildConfigurationList", keyFor("QMAKE_PBX_BUILDCONFIG_LIST")) << ";" << "\n";
+ t << "\t\t\t" << writeSettings("projectDirPath", QStringList()) << ";" << "\n"
+ << "\t\t\t" << writeSettings("targets", project->values("QMAKE_PBX_TARGETS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+
+ //FOOTER
+ t << "\t" << "};" << "\n"
+ << "\t" << writeSettings("rootObject", keyFor("QMAKE_PBX_ROOT")) << ";" << "\n"
+ << "}" << endl;
+
+ if(project->isActiveConfig("generate_pbxbuild_makefile")) {
+ QString mkwrap = fileFixify(pbx_dir + Option::dir_sep + ".." + Option::dir_sep + project->first("MAKEFILE"),
+ qmake_getpwd());
+ QFile mkwrapf(mkwrap);
+ if(mkwrapf.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ writingUnixMakefileGenerator = true;
+ debug_msg(1, "pbuilder: Creating file: %s", mkwrap.toLatin1().constData());
+ QTextStream mkwrapt(&mkwrapf);
+ writeHeader(mkwrapt);
+ const char cleans[] = "preprocess_clean ";
+ mkwrapt << "#This is a makefile wrapper for PROJECT BUILDER\n"
+ << "all:" << "\n\t"
+ << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << "\n"
+ << "install: all" << "\n\t"
+ << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << " install\n"
+ << "distclean clean: preprocess_clean" << "\n\t"
+ << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << " clean" << "\n"
+ << (!did_preprocess ? cleans : "") << ":" << "\n";
+ if(did_preprocess)
+ mkwrapt << cleans << ":" << "\n\t"
+ << "make -f "
+ << pbx_dir << Option::dir_sep << "qt_preprocess.mak $@" << endl;
+ writingUnixMakefileGenerator = false;
+ }
+ }
+ return true;
+}
+
+QString
+ProjectBuilderMakefileGenerator::findProgram(const QString &prog)
+{
+ QString ret = prog;
+ if(QDir::isRelativePath(ret)) {
+ QStringList paths = QString(qgetenv("PATH")).split(':');
+ for(int i = 0; i < paths.size(); ++i) {
+ QString path = paths.at(i) + "/" + prog;
+ if(exists(path)) {
+ ret = path;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+QString
+ProjectBuilderMakefileGenerator::fixForOutput(const QString &values)
+{
+ //get the environment variables references
+ QRegExp reg_var("\\$\\((.*)\\)");
+ for(int rep = 0; (rep = reg_var.indexIn(values, rep)) != -1;) {
+ if(project->values("QMAKE_PBX_VARS").indexOf(reg_var.cap(1)) == -1)
+ project->values("QMAKE_PBX_VARS").append(reg_var.cap(1));
+ rep += reg_var.matchedLength();
+ }
+ QString ret = values;
+ ret = ret.replace(QRegExp("\\\\ "), " "); //unescape spaces
+ ret = ret.replace(QRegExp("('|\\\\|\")"), "\\\\1"); //fix quotes
+ ret = ret.replace("\t", " "); //fix tabs
+ ret = ret.replace(QRegExp(" "), "\\ "); //escape spaces
+ return ret;
+}
+
+QStringList
+ProjectBuilderMakefileGenerator::fixListForOutput(const QString &where)
+{
+ QStringList ret;
+ const QStringList &l = project->values(where);
+ for(int i = 0; i < l.count(); i++)
+ ret += fixForOutput(l[i]);
+ return ret;
+}
+
+QString
+ProjectBuilderMakefileGenerator::keyFor(const QString &block)
+{
+#if 1 //This make this code much easier to debug..
+ if(project->isActiveConfig("no_pb_munge_key"))
+ return block;
+#endif
+ QString ret;
+ if(!keys.contains(block)) {
+ ret = qtMD5(block.toUtf8()).left(24).toUpper();
+ keys.insert(block, ret);
+ } else {
+ ret = keys[block];
+ }
+ return ret;
+}
+
+bool
+ProjectBuilderMakefileGenerator::openOutput(QFile &file, const QString &build) const
+{
+ if(QDir::isRelativePath(file.fileName()))
+ file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run
+ QFileInfo fi(fileInfo(file.fileName()));
+ if(fi.suffix() != "pbxproj" || file.fileName().isEmpty()) {
+ QString output = file.fileName();
+ if(fi.isDir())
+ output += QDir::separator();
+ if(!output.endsWith(projectSuffix())) {
+ if(file.fileName().isEmpty() || fi.isDir()) {
+ if(project->first("TEMPLATE") == "subdirs" || project->isEmpty("QMAKE_ORIG_TARGET"))
+ output += fileInfo(project->projectFile()).baseName();
+ else
+ output += project->first("QMAKE_ORIG_TARGET");
+ }
+ output += projectSuffix() + QDir::separator();
+ } else if(output[(int)output.length() - 1] != QDir::separator()) {
+ output += QDir::separator();
+ }
+ output += QString("project.pbxproj");
+ output = unescapeFilePath(output);
+ file.setFileName(output);
+ }
+ bool ret = UnixMakefileGenerator::openOutput(file, build);
+ ((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir.section(Option::dir_sep, 0, -1);
+ Option::output_dir = pbx_dir.section(Option::dir_sep, 0, -2);
+ return ret;
+}
+
+/* This function is such a hack it is almost pointless, but it
+ eliminates the warning message from ProjectBuilder that the project
+ file is for an older version. I guess this could be used someday if
+ the format of the output is dependant upon the version of
+ ProjectBuilder as well.
+*/
+int
+ProjectBuilderMakefileGenerator::pbuilderVersion() const
+{
+ QString ret;
+ if(!project->isEmpty("QMAKE_PBUILDER_VERSION")) {
+ ret = project->first("QMAKE_PBUILDER_VERSION");
+ } else {
+ QString version, version_plist = project->first("QMAKE_PBUILDER_VERSION_PLIST");
+ if(version_plist.isEmpty()) {
+#ifdef Q_OS_DARWIN
+ ret = QLatin1String("34");
+ QCFType<CFURLRef> cfurl;
+ OSStatus err = LSFindApplicationForInfo(0, CFSTR("com.apple.Xcode"), 0, 0, &cfurl);
+ if (err == noErr) {
+ QCFType<CFBundleRef> bundle = CFBundleCreate(0, cfurl);
+ if (bundle) {
+ CFStringRef str = CFStringRef(CFBundleGetValueForInfoDictionaryKey(bundle,
+ CFSTR("CFBundleShortVersionString")));
+ if (str) {
+ QStringList versions = QCFString::toQString(str).split(QLatin1Char('.'));
+ int versionMajor = versions.at(0).toInt();
+ int versionMinor = versions.at(1).toInt();
+ if (versionMajor >= 2) {
+ ret = QLatin1String("42");
+ } else if (versionMajor == 1 && versionMinor >= 5) {
+ ret = QLatin1String("39");
+ }
+ }
+ }
+ }
+#else
+ if(exists("/Developer/Applications/Xcode.app/Contents/version.plist"))
+ version_plist = "/Developer/Applications/Xcode.app/Contents/version.plist";
+ else
+ version_plist = "/Developer/Applications/Project Builder.app/Contents/version.plist";
+#endif
+ } else {
+ version_plist = version_plist.replace(QRegExp("\""), "");
+ }
+ if (ret.isEmpty()) {
+ QFile version_file(version_plist);
+ if (version_file.open(QIODevice::ReadOnly)) {
+ debug_msg(1, "pbuilder: version.plist: Reading file: %s", version_plist.toLatin1().constData());
+ QTextStream plist(&version_file);
+
+ bool in_dict = false;
+ QString current_key;
+ QRegExp keyreg("^<key>(.*)</key>$"), stringreg("^<string>(.*)</string>$");
+ while(!plist.atEnd()) {
+ QString line = plist.readLine().trimmed();
+ if(line == "<dict>")
+ in_dict = true;
+ else if(line == "</dict>")
+ in_dict = false;
+ else if(in_dict) {
+ if(keyreg.exactMatch(line))
+ current_key = keyreg.cap(1);
+ else if(current_key == "CFBundleShortVersionString" && stringreg.exactMatch(line))
+ version = stringreg.cap(1);
+ }
+ }
+ plist.flush();
+ version_file.close();
+ } else {
+ debug_msg(1, "pbuilder: version.plist: Failure to open %s", version_plist.toLatin1().constData());
+ }
+ if(version.isEmpty() && version_plist.contains("Xcode")) {
+ ret = "39";
+ } else {
+ int versionMajor = version.left(1).toInt();
+ if(versionMajor >= 2)
+ ret = "42";
+ else if(version == "1.5")
+ ret = "39";
+ else if(version == "1.1")
+ ret = "34";
+ }
+ }
+ }
+
+ if(!ret.isEmpty()) {
+ bool ok;
+ int int_ret = ret.toInt(&ok);
+ if(ok) {
+ debug_msg(1, "pbuilder: version.plist: Got version: %d", int_ret);
+ return int_ret;
+ }
+ }
+ debug_msg(1, "pbuilder: version.plist: Fallback to default version");
+ return 42; //my fallback
+}
+
+int
+ProjectBuilderMakefileGenerator::reftypeForFile(const QString &where)
+{
+ int ret = 0; //absolute is the default..
+ if(QDir::isRelativePath(unescapeFilePath(where)))
+ ret = 4; //relative
+ return ret;
+}
+
+QString
+ProjectBuilderMakefileGenerator::projectSuffix() const
+{
+ const int pbVersion = pbuilderVersion();
+ if(pbVersion >= 42)
+ return ".xcodeproj";
+ else if(pbVersion >= 38)
+ return ".xcode";
+ return ".pbproj";
+}
+
+QString
+ProjectBuilderMakefileGenerator::pbxbuild()
+{
+ if(exists("/usr/bin/pbbuild"))
+ return "pbbuild";
+ if(exists("/usr/bin/xcodebuild"))
+ return "xcodebuild";
+ return (pbuilderVersion() >= 38 ? "xcodebuild" : "pbxbuild");
+}
+
+QString
+ProjectBuilderMakefileGenerator::escapeFilePath(const QString &path) const
+{
+#if 1
+ //in the middle of generating a Makefile!
+ if(writingUnixMakefileGenerator)
+ return UnixMakefileGenerator::escapeFilePath(path);
+
+ //generating stuff for the xml file!
+ QString ret = path;
+ if(!ret.isEmpty()) {
+ ret = unescapeFilePath(ret);
+ debug_msg(2, "EscapeFilePath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
+ }
+ return ret;
+#else
+ return UnixMakefileGenerator::escapeFilePath(path);
+#endif
+}
+
+QString
+ProjectBuilderMakefileGenerator::writeSettings(QString var, QStringList vals, int flags, int indent_level)
+{
+ QString ret;
+ const QString quote = (flags & SettingsNoQuote) ? "" : "\"";
+ const QString escape_quote = quote.isEmpty() ? "" : "\\" + quote;
+ QString newline = "\n";
+ for(int i = 0; i < indent_level; ++i)
+ newline += "\t";
+ if(flags & SettingsAsList) {
+ ret += var + " = (" + newline;
+ for(int i = 0, count = 0; i < vals.size(); ++i) {
+ QString val = vals.at(i);
+ if(!val.isEmpty()) {
+ if(count++ > 0)
+ ret += "," + newline;
+ ret += quote + val.replace(quote, escape_quote) + quote;
+ }
+ }
+ ret += ")";
+ } else {
+ ret += var + " = " + quote;
+ for(int i = 0; i < vals.size(); ++i) {
+ QString val = vals.at(i);
+// if(val.isEmpty())
+// val = quote + quote;
+ if(i)
+ ret += " ";
+ ret += val;
+ }
+ ret += quote;
+ }
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/mac/pbuilder_pbx.h b/qmake/generators/mac/pbuilder_pbx.h
new file mode 100644
index 0000000000..c11425a141
--- /dev/null
+++ b/qmake/generators/mac/pbuilder_pbx.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PBUILDER_PBX_H
+#define PBUILDER_PBX_H
+
+#include "unixmake.h"
+
+QT_BEGIN_NAMESPACE
+
+class ProjectBuilderMakefileGenerator : public UnixMakefileGenerator
+{
+ bool writingUnixMakefileGenerator;
+ QString pbx_dir;
+ int pbuilderVersion() const;
+ bool writeSubDirs(QTextStream &);
+ bool writeMakeParts(QTextStream &);
+ bool writeMakefile(QTextStream &);
+
+ QString pbxbuild();
+ QMap<QString, QString> keys;
+ QString keyFor(const QString &file);
+ QString findProgram(const QString &prog);
+ QString fixForOutput(const QString &file);
+ QStringList fixListForOutput(const QString &where);
+ int reftypeForFile(const QString &where);
+ QString projectSuffix() const;
+ enum { SettingsAsList=0x01, SettingsNoQuote=0x02 };
+ inline QString writeSettings(QString var, QString val, int flags=0, int indent_level=0)
+ { Q_UNUSED(indent_level); return writeSettings(var, QStringList(val), flags); }
+ QString writeSettings(QString var, QStringList vals, int flags=0, int indent_level=0);
+
+public:
+ ProjectBuilderMakefileGenerator();
+ ~ProjectBuilderMakefileGenerator();
+
+ virtual bool supportsMetaBuild() { return false; }
+ virtual bool openOutput(QFile &, const QString &) const;
+protected:
+ virtual QString escapeFilePath(const QString &path) const;
+ bool doPrecompiledHeaders() const { return false; }
+ virtual bool doDepends() const { return false; } //never necesary
+};
+
+inline ProjectBuilderMakefileGenerator::~ProjectBuilderMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // PBUILDER_PBX_H
diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp
new file mode 100644
index 0000000000..4f3b1137f5
--- /dev/null
+++ b/qmake/generators/makefile.cpp
@@ -0,0 +1,3297 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "makefile.h"
+#include "option.h"
+#include "cachekeys.h"
+#include "meta.h"
+#include <qdir.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <qhash.h>
+#include <qdebug.h>
+#include <qbuffer.h>
+#include <qsettings.h>
+#include <qdatetime.h>
+#if defined(Q_OS_UNIX)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <qdebug.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+QT_BEGIN_NAMESPACE
+
+// Well, Windows doesn't have this, so here's the macro
+#ifndef S_ISDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+bool MakefileGenerator::canExecute(const QStringList &cmdline, int *a) const
+{
+ int argv0 = -1;
+ for(int i = 0; i < cmdline.count(); ++i) {
+ if(!cmdline.at(i).contains('=')) {
+ argv0 = i;
+ break;
+ }
+ }
+ if(a)
+ *a = argv0;
+ if(argv0 != -1) {
+ const QString c = Option::fixPathToLocalOS(cmdline.at(argv0), true);
+ if(exists(c))
+ return true;
+ }
+ return false;
+}
+
+QString MakefileGenerator::mkdir_p_asstring(const QString &dir, bool escape) const
+{
+ QString ret = "@$(CHK_DIR_EXISTS) ";
+ if(escape)
+ ret += escapeFilePath(dir);
+ else
+ ret += dir;
+ ret += " ";
+ if(isWindowsShell())
+ ret += "$(MKDIR)";
+ else
+ ret += "|| $(MKDIR)";
+ ret += " ";
+ if(escape)
+ ret += escapeFilePath(dir);
+ else
+ ret += dir;
+ ret += " ";
+ return ret;
+}
+
+bool MakefileGenerator::mkdir(const QString &in_path) const
+{
+ QString path = Option::fixPathToLocalOS(in_path);
+ if(QFile::exists(path))
+ return true;
+
+ QDir d;
+ if(path.startsWith(QDir::separator())) {
+ d.cd(QString(QDir::separator()));
+ path.remove(0, 1);
+ }
+ bool ret = true;
+#ifdef Q_OS_WIN
+ bool driveExists = true;
+ if(!QDir::isRelativePath(path)) {
+ if(QFile::exists(path.left(3))) {
+ d.cd(path.left(3));
+ path.remove(0, 3);
+ } else {
+ warn_msg(WarnLogic, "Cannot access drive '%s' (%s)",
+ path.left(3).toLatin1().data(), path.toLatin1().data());
+ driveExists = false;
+ }
+ }
+ if(driveExists)
+#endif
+ {
+ QStringList subs = path.split(QDir::separator());
+ for(QStringList::Iterator subit = subs.begin(); subit != subs.end(); ++subit) {
+ if(!d.cd(*subit)) {
+ d.mkdir((*subit));
+ if(d.exists((*subit))) {
+ d.cd((*subit));
+ } else {
+ ret = false;
+ break;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+// ** base makefile generator
+MakefileGenerator::MakefileGenerator() :
+ init_opath_already(false), init_already(false), no_io(false), project(0)
+{
+}
+
+
+void
+MakefileGenerator::verifyCompilers()
+{
+ QMap<QString, QStringList> &v = project->variables();
+ QStringList &quc = v["QMAKE_EXTRA_COMPILERS"];
+ for(int i = 0; i < quc.size(); ) {
+ bool error = false;
+ QString comp = quc.at(i);
+ if(v[comp + ".output"].isEmpty()) {
+ if(!v[comp + ".output_function"].isEmpty()) {
+ v[comp + ".output"].append("${QMAKE_FUNC_FILE_IN_" + v[comp + ".output_function"].first() + "}");
+ } else {
+ error = true;
+ warn_msg(WarnLogic, "Compiler: %s: No output file specified", comp.toLatin1().constData());
+ }
+ } else if(v[comp + ".input"].isEmpty()) {
+ error = true;
+ warn_msg(WarnLogic, "Compiler: %s: No input variable specified", comp.toLatin1().constData());
+ }
+ if(error)
+ quc.removeAt(i);
+ else
+ ++i;
+ }
+}
+
+void
+MakefileGenerator::initOutPaths()
+{
+ if(init_opath_already)
+ return;
+ verifyCompilers();
+ init_opath_already = true;
+ QMap<QString, QStringList> &v = project->variables();
+ //for shadow builds
+ if(!v.contains("QMAKE_ABSOLUTE_SOURCE_PATH")) {
+ if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty() &&
+ v.contains("QMAKE_ABSOLUTE_SOURCE_ROOT")) {
+ QString root = v["QMAKE_ABSOLUTE_SOURCE_ROOT"].first();
+ root = QDir::fromNativeSeparators(root);
+ if(!root.isEmpty()) {
+ QFileInfo fi = fileInfo(Option::mkfile::cachefile);
+ if(!fi.makeAbsolute()) {
+ QString cache_r = fi.path(), pwd = Option::output_dir;
+ if(pwd.startsWith(cache_r) && !pwd.startsWith(root)) {
+ pwd = root + pwd.mid(cache_r.length());
+ if(exists(pwd))
+ v.insert("QMAKE_ABSOLUTE_SOURCE_PATH", QStringList(pwd));
+ }
+ }
+ }
+ }
+ }
+ if(!v["QMAKE_ABSOLUTE_SOURCE_PATH"].isEmpty()) {
+ QString &asp = v["QMAKE_ABSOLUTE_SOURCE_PATH"].first();
+ asp = QDir::fromNativeSeparators(asp);
+ if(asp.isEmpty() || asp == Option::output_dir) //if they're the same, why bother?
+ v["QMAKE_ABSOLUTE_SOURCE_PATH"].clear();
+ }
+
+ QString currentDir = qmake_getpwd(); //just to go back to
+
+ //some builtin directories
+ if(project->isEmpty("PRECOMPILED_DIR") && !project->isEmpty("OBJECTS_DIR"))
+ 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() };
+ for(int x = 0; !dirs[x].isEmpty(); x++) {
+ if(v[dirs[x]].isEmpty())
+ continue;
+ const QString orig_path = v[dirs[x]].first();
+
+ QString &pathRef = v[dirs[x]].first();
+ pathRef = fileFixify(pathRef, Option::output_dir, Option::output_dir);
+
+#ifdef Q_OS_WIN
+ // We don't want to add a separator for DLLDESTDIR on Windows (###why?)
+ if(!(dirs[x] == "DLLDESTDIR"))
+#endif
+ {
+ if(!pathRef.endsWith(Option::dir_sep))
+ pathRef += Option::dir_sep;
+ }
+
+ if(noIO())
+ continue;
+
+ QString path = project->first(dirs[x]); //not to be changed any further
+ path = fileFixify(path, currentDir, Option::output_dir);
+ debug_msg(3, "Fixed output_dir %s (%s) into %s", dirs[x].toLatin1().constData(),
+ orig_path.toLatin1().constData(), path.toLatin1().constData());
+ if(!mkdir(path))
+ warn_msg(WarnLogic, "%s: Cannot access directory '%s'", dirs[x].toLatin1().constData(),
+ path.toLatin1().constData());
+ }
+
+ //out paths from the extra compilers
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = project->values((*it) + ".output").first();
+ if(tmp_out.isEmpty())
+ continue;
+ const QStringList &tmp = project->values((*it) + ".input");
+ for(QStringList::ConstIterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
+ QStringList &inputs = project->values((*it2));
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
+ (*input) = fileFixify((*input), Option::output_dir, Option::output_dir);
+ QString path = unescapeFilePath(replaceExtraCompilerVariables(tmp_out, (*input), QString()));
+ path = Option::fixPathToTargetOS(path);
+ int slash = path.lastIndexOf(Option::dir_sep);
+ if(slash != -1) {
+ path = path.left(slash);
+ // Make out path only if it does not contain makefile variables
+ if(!path.contains("${"))
+ if(path != "." &&
+ !mkdir(fileFixify(path, qmake_getpwd(), Option::output_dir)))
+ warn_msg(WarnLogic, "%s: Cannot access directory '%s'",
+ (*it).toLatin1().constData(), path.toLatin1().constData());
+ }
+ }
+ }
+ }
+
+ if(!v["DESTDIR"].isEmpty()) {
+ QDir d(v["DESTDIR"].first());
+ if(Option::fixPathToLocalOS(d.absolutePath()) == Option::fixPathToLocalOS(Option::output_dir))
+ v.remove("DESTDIR");
+ }
+}
+
+QMakeProject
+*MakefileGenerator::projectFile() const
+{
+ return project;
+}
+
+void
+MakefileGenerator::setProjectFile(QMakeProject *p)
+{
+ if(project)
+ return;
+ project = p;
+ init();
+ usePlatformDir();
+ findLibraries();
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE &&
+ project->isActiveConfig("link_prl")) //load up prl's'
+ processPrlFiles();
+}
+
+QStringList
+MakefileGenerator::findFilesInVPATH(QStringList l, uchar flags, const QString &vpath_var)
+{
+ QStringList vpath;
+ QMap<QString, QStringList> &v = project->variables();
+ for(int val_it = 0; val_it < l.count(); ) {
+ bool remove_file = false;
+ QString &val = l[val_it];
+ if(!val.isEmpty()) {
+ QString file = fixEnvVariables(val);
+ if(!(flags & VPATH_NoFixify))
+ file = fileFixify(file, qmake_getpwd(), Option::output_dir);
+ if (file.at(0) == '\"' && file.at(file.length() - 1) == '\"')
+ file = file.mid(1, file.length() - 2);
+
+ if(exists(file)) {
+ ++val_it;
+ continue;
+ }
+ bool found = false;
+ if(QDir::isRelativePath(val)) {
+ if(vpath.isEmpty()) {
+ if(!vpath_var.isEmpty())
+ vpath = v[vpath_var];
+ vpath += v["VPATH"] + v["QMAKE_ABSOLUTE_SOURCE_PATH"] + v["DEPENDPATH"];
+ if(Option::output_dir != qmake_getpwd())
+ vpath += Option::output_dir;
+ }
+ for(QStringList::Iterator vpath_it = vpath.begin();
+ vpath_it != vpath.end(); ++vpath_it) {
+ QString real_dir = Option::fixPathToLocalOS((*vpath_it));
+ if(exists(real_dir + QDir::separator() + val)) {
+ QString dir = (*vpath_it);
+ if(!dir.endsWith(Option::dir_sep))
+ dir += Option::dir_sep;
+ val = dir + val;
+ if(!(flags & VPATH_NoFixify))
+ val = fileFixify(val);
+ found = true;
+ debug_msg(1, "Found file through vpath %s -> %s",
+ file.toLatin1().constData(), val.toLatin1().constData());
+ break;
+ }
+ }
+ }
+ if(!found) {
+ QString dir, regex = val, real_dir;
+ if(regex.lastIndexOf(Option::dir_sep) != -1) {
+ dir = regex.left(regex.lastIndexOf(Option::dir_sep) + 1);
+ real_dir = dir;
+ if(!(flags & VPATH_NoFixify))
+ real_dir = fileFixify(real_dir, qmake_getpwd(), Option::output_dir) + '/';
+ regex.remove(0, dir.length());
+ }
+ if(real_dir.isEmpty() || exists(real_dir)) {
+ QStringList files = QDir(real_dir).entryList(QStringList(regex));
+ if(files.isEmpty()) {
+ debug_msg(1, "%s:%d Failure to find %s in vpath (%s)",
+ __FILE__, __LINE__,
+ val.toLatin1().constData(), vpath.join("::").toLatin1().constData());
+ if(flags & VPATH_RemoveMissingFiles)
+ remove_file = true;
+ else if(flags & VPATH_WarnMissingFiles)
+ warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData());
+ } else {
+ l.removeAt(val_it);
+ QString a;
+ for(int i = (int)files.count()-1; i >= 0; i--) {
+ if(files[i] == "." || files[i] == "..")
+ continue;
+ a = real_dir + files[i];
+ if(!(flags & VPATH_NoFixify))
+ a = fileFixify(a);
+ l.insert(val_it, a);
+ }
+ }
+ } else {
+ debug_msg(1, "%s:%d Cannot match %s%s, as %s does not exist.",
+ __FILE__, __LINE__, real_dir.toLatin1().constData(),
+ regex.toLatin1().constData(), real_dir.toLatin1().constData());
+ if(flags & VPATH_RemoveMissingFiles)
+ remove_file = true;
+ else if(flags & VPATH_WarnMissingFiles)
+ warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData());
+ }
+ }
+ }
+ if(remove_file)
+ l.removeAt(val_it);
+ else
+ ++val_it;
+ }
+ return l;
+}
+
+void
+MakefileGenerator::initCompiler(const MakefileGenerator::Compiler &comp)
+{
+ QMap<QString, QStringList> &v = project->variables();
+ QStringList &l = v[comp.variable_in];
+ // find all the relevant file inputs
+ if(!init_compiler_already.contains(comp.variable_in)) {
+ init_compiler_already.insert(comp.variable_in, true);
+ if(!noIO())
+ l = findFilesInVPATH(l, (comp.flags & Compiler::CompilerRemoveNoExist) ?
+ VPATH_RemoveMissingFiles : VPATH_WarnMissingFiles, "VPATH_" + comp.variable_in);
+ }
+}
+
+void
+MakefileGenerator::init()
+{
+ initOutPaths();
+ if(init_already)
+ return;
+ verifyCompilers();
+ init_already = true;
+
+ QMap<QString, QStringList> &v = project->variables();
+ QStringList &quc = v["QMAKE_EXTRA_COMPILERS"];
+
+ //make sure the COMPILERS are in the correct input/output chain order
+ for(int comp_out = 0, jump_count = 0; comp_out < quc.size(); ++comp_out) {
+ continue_compiler_chain:
+ if(jump_count > quc.size()) //just to avoid an infinite loop here
+ break;
+ if(project->variables().contains(quc.at(comp_out) + ".variable_out")) {
+ const QStringList &outputs = project->variables().value(quc.at(comp_out) + ".variable_out");
+ for(int out = 0; out < outputs.size(); ++out) {
+ for(int comp_in = 0; comp_in < quc.size(); ++comp_in) {
+ if(comp_in == comp_out)
+ continue;
+ if(project->variables().contains(quc.at(comp_in) + ".input")) {
+ const QStringList &inputs = project->variables().value(quc.at(comp_in) + ".input");
+ for(int in = 0; in < inputs.size(); ++in) {
+ if(inputs.at(in) == outputs.at(out) && comp_out > comp_in) {
+ ++jump_count;
+ //move comp_out to comp_in and continue the compiler chain
+ quc.move(comp_out, comp_in);
+ comp_out = comp_in;
+ goto continue_compiler_chain;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(!project->isEmpty("QMAKE_SUBSTITUTES")) {
+ const QStringList &subs = v["QMAKE_SUBSTITUTES"];
+ for(int i = 0; i < subs.size(); ++i) {
+ QString inn = subs.at(i) + ".input", outn = subs.at(i) + ".output";
+ if (v.contains(inn) || v.contains(outn)) {
+ if (!v.contains(inn) || !v.contains(outn)) {
+ warn_msg(WarnLogic, "Substitute '%s' has only one of .input and .output",
+ subs.at(i).toLatin1().constData());
+ continue;
+ }
+ const QStringList &tinn = v[inn], &toutn = v[outn];
+ if (tinn.length() != 1) {
+ warn_msg(WarnLogic, "Substitute '%s.input' does not have exactly one value",
+ subs.at(i).toLatin1().constData());
+ continue;
+ }
+ if (toutn.length() != 1) {
+ warn_msg(WarnLogic, "Substitute '%s.output' does not have exactly one value",
+ subs.at(i).toLatin1().constData());
+ continue;
+ }
+ inn = fileFixify(tinn.first(), qmake_getpwd());
+ outn = fileFixify(toutn.first(), qmake_getpwd(), Option::output_dir);
+ } else {
+ inn = fileFixify(subs.at(i), qmake_getpwd());
+ if (!QFile::exists(inn)) {
+ // random insanity for backwards compat: .in file specified with absolute out dir
+ inn = fileFixify(subs.at(i));
+ }
+ if(!inn.endsWith(".in")) {
+ warn_msg(WarnLogic, "Substitute '%s' does not end with '.in'",
+ inn.toLatin1().constData());
+ continue;
+ }
+ outn = fileFixify(inn.left(inn.length()-3), qmake_getpwd(), Option::output_dir);
+ }
+ QFile in(inn);
+ if(in.open(QFile::ReadOnly)) {
+ QString contents;
+ QStack<int> state;
+ enum { IN_CONDITION, MET_CONDITION, PENDING_CONDITION };
+ for(int count = 1; !in.atEnd(); ++count) {
+ QString line = QString::fromUtf8(in.readLine());
+ if(line.startsWith("!!IF ")) {
+ if(state.isEmpty() || state.top() == IN_CONDITION) {
+ QString test = line.mid(5, line.length()-(5+1));
+ if(project->test(test))
+ state.push(IN_CONDITION);
+ else
+ state.push(PENDING_CONDITION);
+ } else {
+ state.push(MET_CONDITION);
+ }
+ } else if(line.startsWith("!!ELIF ")) {
+ if(state.isEmpty()) {
+ warn_msg(WarnLogic, "(%s:%d): Unexpected else condition",
+ in.fileName().toLatin1().constData(), count);
+ } else if(state.top() == PENDING_CONDITION) {
+ QString test = line.mid(7, line.length()-(7+1));
+ if(project->test(test)) {
+ state.pop();
+ state.push(IN_CONDITION);
+ }
+ } else if(state.top() == IN_CONDITION) {
+ state.pop();
+ state.push(MET_CONDITION);
+ }
+ } else if(line.startsWith("!!ELSE")) {
+ if(state.isEmpty()) {
+ warn_msg(WarnLogic, "(%s:%d): Unexpected else condition",
+ in.fileName().toLatin1().constData(), count);
+ } else if(state.top() == PENDING_CONDITION) {
+ state.pop();
+ state.push(IN_CONDITION);
+ } else if(state.top() == IN_CONDITION) {
+ state.pop();
+ state.push(MET_CONDITION);
+ }
+ } else if(line.startsWith("!!ENDIF")) {
+ if(state.isEmpty())
+ warn_msg(WarnLogic, "(%s:%d): Unexpected endif",
+ in.fileName().toLatin1().constData(), count);
+ else
+ state.pop();
+ } else if(state.isEmpty() || state.top() == IN_CONDITION) {
+ contents += project->expand(line, in.fileName(), count);
+ }
+ }
+ QFile out(outn);
+ if(out.exists() && out.open(QFile::ReadOnly)) {
+ QString old = QString::fromUtf8(out.readAll());
+ if(contents == old) {
+ v["QMAKE_INTERNAL_INCLUDED_FILES"].append(in.fileName());
+ continue;
+ }
+ out.close();
+ if(!out.remove()) {
+ warn_msg(WarnLogic, "Cannot clear substitute '%s'",
+ out.fileName().toLatin1().constData());
+ continue;
+ }
+ }
+ mkdir(QFileInfo(out).absolutePath());
+ if(out.open(QFile::WriteOnly)) {
+ v["QMAKE_INTERNAL_INCLUDED_FILES"].append(in.fileName());
+ out.write(contents.toUtf8());
+ } else {
+ warn_msg(WarnLogic, "Cannot open substitute for output '%s'",
+ out.fileName().toLatin1().constData());
+ }
+ } else {
+ warn_msg(WarnLogic, "Cannot open substitute for input '%s'",
+ in.fileName().toLatin1().constData());
+ }
+ }
+ }
+
+ int x;
+
+ //build up a list of compilers
+ QList<Compiler> compilers;
+ {
+ const char *builtins[] = { "OBJECTS", "SOURCES", "PRECOMPILED_HEADER", 0 };
+ for(x = 0; builtins[x]; ++x) {
+ Compiler compiler;
+ compiler.variable_in = builtins[x];
+ compiler.flags = Compiler::CompilerBuiltin;
+ compiler.type = QMakeSourceFileInfo::TYPE_C;
+ if(!strcmp(builtins[x], "OBJECTS"))
+ compiler.flags |= Compiler::CompilerNoCheckDeps;
+ compilers.append(compiler);
+ }
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const QStringList &inputs = v[(*it) + ".input"];
+ for(x = 0; x < inputs.size(); ++x) {
+ Compiler compiler;
+ compiler.variable_in = inputs.at(x);
+ compiler.flags = Compiler::CompilerNoFlags;
+ if(v[(*it) + ".CONFIG"].indexOf("ignore_no_exist") != -1)
+ compiler.flags |= Compiler::CompilerRemoveNoExist;
+ if(v[(*it) + ".CONFIG"].indexOf("no_dependencies") != -1)
+ compiler.flags |= Compiler::CompilerNoCheckDeps;
+
+ QString dep_type;
+ if(!project->isEmpty((*it) + ".dependency_type"))
+ dep_type = project->first((*it) + ".dependency_type");
+ if (dep_type.isEmpty())
+ compiler.type = QMakeSourceFileInfo::TYPE_UNKNOWN;
+ else if(dep_type == "TYPE_UI")
+ compiler.type = QMakeSourceFileInfo::TYPE_UI;
+ else
+ compiler.type = QMakeSourceFileInfo::TYPE_C;
+ compilers.append(compiler);
+ }
+ }
+ }
+ { //do the path fixifying
+ QStringList paths;
+ for(x = 0; x < compilers.count(); ++x) {
+ if(!paths.contains(compilers.at(x).variable_in))
+ paths << compilers.at(x).variable_in;
+ }
+ paths << "INCLUDEPATH" << "QMAKE_INTERNAL_INCLUDED_FILES" << "PRECOMPILED_HEADER";
+ for(int y = 0; y < paths.count(); y++) {
+ QStringList &l = v[paths[y]];
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ if((*it).isEmpty())
+ continue;
+ if(exists((*it)))
+ (*it) = fileFixify((*it));
+ }
+ }
+ }
+
+ if(noIO() || !doDepends())
+ QMakeSourceFileInfo::setDependencyMode(QMakeSourceFileInfo::NonRecursive);
+ for(x = 0; x < compilers.count(); ++x)
+ initCompiler(compilers.at(x));
+
+ //merge actual compiler outputs into their variable_out. This is done last so that
+ //files are already properly fixified.
+ for(QStringList::Iterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = project->values((*it) + ".output").first();
+ if(tmp_out.isEmpty())
+ continue;
+ if(project->values((*it) + ".CONFIG").indexOf("combine") != -1) {
+ QStringList &compilerInputs = project->values((*it) + ".input");
+ // Don't generate compiler output if it doesn't have input.
+ if (compilerInputs.isEmpty() || project->values(compilerInputs.first()).isEmpty())
+ continue;
+ if(tmp_out.indexOf("$") == -1) {
+ if(!verifyExtraCompiler((*it), QString())) //verify
+ continue;
+ QString out = fileFixify(tmp_out, Option::output_dir, Option::output_dir);
+ bool pre_dep = (project->values((*it) + ".CONFIG").indexOf("target_predeps") != -1);
+ if(project->variables().contains((*it) + ".variable_out")) {
+ const QStringList &var_out = project->variables().value((*it) + ".variable_out");
+ for(int i = 0; i < var_out.size(); ++i) {
+ QString v = var_out.at(i);
+ if(v == QLatin1String("SOURCES"))
+ v = "GENERATED_SOURCES";
+ else if(v == QLatin1String("OBJECTS"))
+ pre_dep = false;
+ QStringList &list = project->values(v);
+ if(!list.contains(out))
+ list.append(out);
+ }
+ } else if(project->values((*it) + ".CONFIG").indexOf("no_link") == -1) {
+ QStringList &list = project->values("OBJECTS");
+ pre_dep = false;
+ if(!list.contains(out))
+ list.append(out);
+ } else {
+ QStringList &list = project->values("UNUSED_SOURCES");
+ if(!list.contains(out))
+ list.append(out);
+ }
+ if(pre_dep) {
+ QStringList &list = project->variables()["PRE_TARGETDEPS"];
+ if(!list.contains(out))
+ list.append(out);
+ }
+ }
+ } else {
+ QStringList &tmp = project->values((*it) + ".input");
+ for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
+ const QStringList inputs = project->values((*it2));
+ for(QStringList::ConstIterator input = inputs.constBegin(); input != inputs.constEnd(); ++input) {
+ if((*input).isEmpty())
+ continue;
+ QString in = Option::fixPathToTargetOS((*input), false);
+ if(!verifyExtraCompiler((*it), in)) //verify
+ continue;
+ QString out = replaceExtraCompilerVariables(tmp_out, (*input), QString());
+ out = fileFixify(out, Option::output_dir, Option::output_dir);
+ bool pre_dep = (project->values((*it) + ".CONFIG").indexOf("target_predeps") != -1);
+ if(project->variables().contains((*it) + ".variable_out")) {
+ const QStringList &var_out = project->variables().value((*it) + ".variable_out");
+ for(int i = 0; i < var_out.size(); ++i) {
+ QString v = var_out.at(i);
+ if(v == QLatin1String("SOURCES"))
+ v = "GENERATED_SOURCES";
+ else if(v == QLatin1String("OBJECTS"))
+ pre_dep = false;
+ QStringList &list = project->values(v);
+ if(!list.contains(out))
+ list.append(out);
+ }
+ } else if(project->values((*it) + ".CONFIG").indexOf("no_link") == -1) {
+ pre_dep = false;
+ QStringList &list = project->values("OBJECTS");
+ if(!list.contains(out))
+ list.append(out);
+ } else {
+ QStringList &list = project->values("UNUSED_SOURCES");
+ if(!list.contains(out))
+ list.append(out);
+ }
+ if(pre_dep) {
+ QStringList &list = project->variables()["PRE_TARGETDEPS"];
+ if(!list.contains(out))
+ list.append(out);
+ }
+ }
+ }
+ }
+ }
+
+ //handle dependencies
+ depHeuristicsCache.clear();
+ if(!noIO()) {
+ // dependency paths
+ QStringList incDirs = v["DEPENDPATH"] + v["QMAKE_ABSOLUTE_SOURCE_PATH"];
+ if(project->isActiveConfig("depend_includepath"))
+ incDirs += v["INCLUDEPATH"];
+ if(!project->isActiveConfig("no_include_pwd")) {
+ QString pwd = qmake_getpwd();
+ if(pwd.isEmpty())
+ pwd = ".";
+ incDirs += pwd;
+ }
+ QList<QMakeLocalFileName> deplist;
+ for(QStringList::Iterator it = incDirs.begin(); it != incDirs.end(); ++it)
+ deplist.append(QMakeLocalFileName(unescapeFilePath((*it))));
+ QMakeSourceFileInfo::setDependencyPaths(deplist);
+ debug_msg(1, "Dependency Directories: %s", incDirs.join(" :: ").toLatin1().constData());
+ //cache info
+ if(project->isActiveConfig("qmake_cache")) {
+ QString cache_file;
+ if(!project->isEmpty("QMAKE_INTERNAL_CACHE_FILE")) {
+ cache_file = QDir::fromNativeSeparators(project->first("QMAKE_INTERNAL_CACHE_FILE"));
+ } else {
+ cache_file = ".qmake.internal.cache";
+ if(project->isActiveConfig("build_pass"))
+ cache_file += ".BUILD." + project->first("BUILD_PASS");
+ }
+ if(cache_file.indexOf('/') == -1)
+ cache_file.prepend(Option::output_dir + '/');
+ QMakeSourceFileInfo::setCacheFile(cache_file);
+ }
+
+ //add to dependency engine
+ for(x = 0; x < compilers.count(); ++x) {
+ const MakefileGenerator::Compiler &comp = compilers.at(x);
+ if(!(comp.flags & Compiler::CompilerNoCheckDeps))
+ addSourceFiles(v[comp.variable_in], QMakeSourceFileInfo::SEEK_DEPS,
+ (QMakeSourceFileInfo::SourceFileType)comp.type);
+ }
+ }
+
+ processSources(); //remove anything in SOURCES which is included (thus it need not be linked in)
+
+ //all sources and generated sources must be turned into objects at some point (the one builtin compiler)
+ v["OBJECTS"] += createObjectList(v["SOURCES"]) + createObjectList(v["GENERATED_SOURCES"]);
+
+ //Translation files
+ if(!project->isEmpty("TRANSLATIONS")) {
+ QStringList &trf = project->values("TRANSLATIONS");
+ for(QStringList::Iterator it = trf.begin(); it != trf.end(); ++it)
+ (*it) = Option::fixPathToLocalOS((*it));
+ }
+
+ { //get the output_dir into the pwd
+ if(Option::output_dir != qmake_getpwd())
+ project->values("INCLUDEPATH").append(".");
+ }
+
+ //fix up the target deps
+ QString fixpaths[] = { QString("PRE_TARGETDEPS"), QString("POST_TARGETDEPS"), QString() };
+ for(int path = 0; !fixpaths[path].isNull(); path++) {
+ QStringList &l = v[fixpaths[path]];
+ for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
+ if(!(*val_it).isEmpty())
+ (*val_it) = escapeDependencyPath(Option::fixPathToTargetOS((*val_it), false, false));
+ }
+ }
+
+ //extra depends
+ if(!project->isEmpty("DEPENDS")) {
+ QStringList &l = v["DEPENDS"];
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QStringList files = v[(*it) + ".file"] + v[(*it) + ".files"]; //why do I support such evil things?
+ for(QStringList::Iterator file_it = files.begin(); file_it != files.end(); ++file_it) {
+ QStringList &out_deps = findDependencies(*file_it);
+ QStringList &in_deps = v[(*it) + ".depends"]; //even more evilness..
+ for(QStringList::Iterator dep_it = in_deps.begin(); dep_it != in_deps.end(); ++dep_it) {
+ if(exists(*dep_it)) {
+ out_deps.append(*dep_it);
+ } else {
+ QString dir, regex = Option::fixPathToLocalOS((*dep_it));
+ if(regex.lastIndexOf(Option::dir_sep) != -1) {
+ dir = regex.left(regex.lastIndexOf(Option::dir_sep) + 1);
+ regex.remove(0, dir.length());
+ }
+ QStringList files = QDir(dir).entryList(QStringList(regex));
+ if(files.isEmpty()) {
+ warn_msg(WarnLogic, "Dependency for [%s]: Not found %s", (*file_it).toLatin1().constData(),
+ (*dep_it).toLatin1().constData());
+ } else {
+ for(int i = 0; i < files.count(); i++)
+ out_deps.append(dir + files[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // escape qmake command
+ QStringList &qmk = project->values("QMAKE_QMAKE");
+ qmk = escapeFilePaths(qmk);
+}
+
+bool
+MakefileGenerator::processPrlFile(QString &file)
+{
+ bool ret = false, try_replace_file=false;
+ QString meta_file, orig_file = file;
+ if(QMakeMetaInfo::libExists(file)) {
+ try_replace_file = true;
+ meta_file = file;
+ file = "";
+ } else {
+ QString tmp = file;
+ int ext = tmp.lastIndexOf('.');
+ if(ext != -1)
+ tmp = tmp.left(ext);
+ meta_file = tmp;
+ }
+// meta_file = fileFixify(meta_file);
+ QString real_meta_file = Option::fixPathToLocalOS(meta_file);
+ if(!meta_file.isEmpty()) {
+ QString f = fileFixify(real_meta_file, qmake_getpwd(), Option::output_dir);
+ if(QMakeMetaInfo::libExists(f)) {
+ QMakeMetaInfo libinfo;
+ debug_msg(1, "Processing PRL file: %s", real_meta_file.toLatin1().constData());
+ if(!libinfo.readLib(f)) {
+ fprintf(stderr, "Error processing meta file: %s\n", real_meta_file.toLatin1().constData());
+ } else if(project->isActiveConfig("no_read_prl_" + libinfo.type().toLower())) {
+ debug_msg(2, "Ignored meta file %s [%s]", real_meta_file.toLatin1().constData(), libinfo.type().toLatin1().constData());
+ } else {
+ ret = true;
+ QMap<QString, QStringList> &vars = libinfo.variables();
+ for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it)
+ processPrlVariable(it.key(), it.value());
+ if(try_replace_file && !libinfo.isEmpty("QMAKE_PRL_TARGET")) {
+ QString dir;
+ int slsh = real_meta_file.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ dir = real_meta_file.left(slsh+1);
+ file = libinfo.first("QMAKE_PRL_TARGET");
+ if(QDir::isRelativePath(file))
+ file.prepend(dir);
+ }
+ }
+ }
+ if(ret) {
+ QString mf = QMakeMetaInfo::findLib(meta_file);
+ if(project->values("QMAKE_PRL_INTERNAL_FILES").indexOf(mf) == -1)
+ project->values("QMAKE_PRL_INTERNAL_FILES").append(mf);
+ if(project->values("QMAKE_INTERNAL_INCLUDED_FILES").indexOf(mf) == -1)
+ project->values("QMAKE_INTERNAL_INCLUDED_FILES").append(mf);
+ }
+ }
+ if(try_replace_file && file.isEmpty()) {
+#if 0
+ warn_msg(WarnLogic, "Found prl [%s] file with no target [%s]!", meta_file.toLatin1().constData(),
+ orig_file.toLatin1().constData());
+#endif
+ file = orig_file;
+ }
+ return ret;
+}
+
+void
+MakefileGenerator::filterIncludedFiles(const QString &var)
+{
+ QStringList &inputs = project->values(var);
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ) {
+ if(QMakeSourceFileInfo::included((*input)) > 0)
+ input = inputs.erase(input);
+ else
+ ++input;
+ }
+}
+
+void
+MakefileGenerator::processPrlVariable(const QString &var, const QStringList &l)
+{
+ if(var == "QMAKE_PRL_LIBS") {
+ QString where = "QMAKE_LIBS";
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ where = project->first("QMAKE_INTERNAL_PRL_LIBS");
+ QStringList &out = project->values(where);
+ for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
+ if(out.indexOf((*it)) == -1)
+ out.append((*it));
+ }
+ } else if(var == "QMAKE_PRL_DEFINES") {
+ QStringList &out = project->values("DEFINES");
+ for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
+ if(out.indexOf((*it)) == -1 &&
+ project->values("PRL_EXPORT_DEFINES").indexOf((*it)) == -1)
+ out.append((*it));
+ }
+ }
+}
+
+void
+MakefileGenerator::processPrlFiles()
+{
+ QHash<QString, bool> processed;
+ for(bool ret = false; true; ret = false) {
+ //read in any prl files included..
+ QStringList l_out;
+ QString where = "QMAKE_LIBS";
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ where = project->first("QMAKE_INTERNAL_PRL_LIBS");
+ QStringList &l = project->values(where);
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString file = (*it);
+ if(!processed.contains(file) && processPrlFile(file)) {
+ processed.insert(file, true);
+ ret = true;
+ }
+ if(!file.isEmpty())
+ l_out.append(file);
+ }
+ if(ret)
+ l = l_out;
+ else
+ break;
+ }
+}
+
+void
+MakefileGenerator::writePrlFile(QTextStream &t)
+{
+ QString target = project->first("TARGET");
+ int slsh = target.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ target.remove(0, slsh + 1);
+ QString bdir = Option::output_dir;
+ if(bdir.isEmpty())
+ bdir = qmake_getpwd();
+ t << "QMAKE_PRL_BUILD_DIR = " << bdir << endl;
+
+ if(!project->projectFile().isEmpty() && project->projectFile() != "-")
+ t << "QMAKE_PRO_INPUT = " << project->projectFile().section('/', -1) << endl;
+
+ if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
+ t << "QMAKE_PRL_SOURCE_DIR = " << project->first("QMAKE_ABSOLUTE_SOURCE_PATH") << endl;
+ t << "QMAKE_PRL_TARGET = " << target << endl;
+ if(!project->isEmpty("PRL_EXPORT_DEFINES"))
+ t << "QMAKE_PRL_DEFINES = " << project->values("PRL_EXPORT_DEFINES").join(" ") << endl;
+ if(!project->isEmpty("PRL_EXPORT_CFLAGS"))
+ t << "QMAKE_PRL_CFLAGS = " << project->values("PRL_EXPORT_CFLAGS").join(" ") << endl;
+ if(!project->isEmpty("PRL_EXPORT_CXXFLAGS"))
+ t << "QMAKE_PRL_CXXFLAGS = " << project->values("PRL_EXPORT_CXXFLAGS").join(" ") << endl;
+ if(!project->isEmpty("CONFIG"))
+ t << "QMAKE_PRL_CONFIG = " << project->values("CONFIG").join(" ") << endl;
+ if(!project->isEmpty("TARGET_VERSION_EXT"))
+ t << "QMAKE_PRL_VERSION = " << project->first("TARGET_VERSION_EXT") << endl;
+ else if(!project->isEmpty("VERSION"))
+ t << "QMAKE_PRL_VERSION = " << project->first("VERSION") << endl;
+ if(project->isActiveConfig("staticlib") || project->isActiveConfig("explicitlib")) {
+ QStringList libs;
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ libs = project->values("QMAKE_INTERNAL_PRL_LIBS");
+ else
+ libs << "QMAKE_LIBS"; //obvious one
+ if(project->isActiveConfig("staticlib"))
+ libs << "QMAKE_LIBS_PRIVATE";
+ t << "QMAKE_PRL_LIBS = ";
+ for(QStringList::Iterator it = libs.begin(); it != libs.end(); ++it)
+ t << project->values((*it)).join(" ").replace('\\', "\\\\") << " ";
+ t << endl;
+ }
+}
+
+bool
+MakefileGenerator::writeProjectMakefile()
+{
+ usePlatformDir();
+ QTextStream t(&Option::output);
+
+ //header
+ writeHeader(t);
+
+ QList<SubTarget*> targets;
+ {
+ QStringList builds = project->values("BUILDS");
+ for(QStringList::Iterator it = builds.begin(); it != builds.end(); ++it) {
+ SubTarget *st = new SubTarget;
+ targets.append(st);
+ st->makefile = "$(MAKEFILE)." + (*it);
+ st->name = (*it);
+ st->target = project->isEmpty((*it) + ".target") ? (*it) : project->first((*it) + ".target");
+ }
+ }
+ if(project->isActiveConfig("build_all")) {
+ t << "first: all" << endl;
+ QList<SubTarget*>::Iterator it;
+
+ //install
+ t << "install: ";
+ for(it = targets.begin(); it != targets.end(); ++it)
+ t << (*it)->target << "-install ";
+ t << endl;
+
+ //uninstall
+ t << "uninstall: ";
+ for(it = targets.begin(); it != targets.end(); ++it)
+ t << (*it)->target << "-uninstall ";
+ t << endl;
+ } else {
+ t << "first: " << targets.first()->target << endl
+ << "install: " << targets.first()->target << "-install" << endl
+ << "uninstall: " << targets.first()->target << "-uninstall" << endl;
+ }
+
+ writeSubTargets(t, targets, SubTargetsNoFlags);
+ if(!project->isActiveConfig("no_autoqmake")) {
+ for(QList<SubTarget*>::Iterator it = targets.begin(); it != targets.end(); ++it)
+ t << (*it)->makefile << ": " <<
+ Option::fixPathToTargetOS(fileFixify(Option::output.fileName())) << endl;
+ }
+ qDeleteAll(targets);
+ return true;
+}
+
+bool
+MakefileGenerator::write()
+{
+ if(!project)
+ return false;
+ writePrlFile();
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || //write makefile
+ Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
+ QTextStream t(&Option::output);
+ if(!writeMakefile(t)) {
+#if 1
+ warn_msg(WarnLogic, "Unable to generate output for: %s [TEMPLATE %s]",
+ Option::output.fileName().toLatin1().constData(),
+ project->first("TEMPLATE").toLatin1().constData());
+ if(Option::output.exists())
+ Option::output.remove();
+#endif
+ }
+ }
+ return true;
+}
+
+QString
+MakefileGenerator::prlFileName(bool fixify)
+{
+ QString ret = project->first("TARGET_PRL");;
+ if(ret.isEmpty())
+ ret = project->first("TARGET");
+ int slsh = ret.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ ret.remove(0, slsh);
+ if(!ret.endsWith(Option::prl_ext)) {
+ int dot = ret.indexOf('.');
+ if(dot != -1)
+ ret.truncate(dot);
+ ret += Option::prl_ext;
+ }
+ if(!project->isEmpty("QMAKE_BUNDLE"))
+ ret.prepend(project->first("QMAKE_BUNDLE") + Option::dir_sep);
+ if(fixify) {
+ if(!project->isEmpty("DESTDIR"))
+ ret.prepend(project->first("DESTDIR"));
+ ret = Option::fixPathToLocalOS(fileFixify(ret, qmake_getpwd(), Option::output_dir));
+ }
+ return ret;
+}
+
+void
+MakefileGenerator::writePrlFile()
+{
+ if((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+ Option::qmake_mode == Option::QMAKE_GENERATE_PRL)
+ && project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()
+ && project->isActiveConfig("create_prl")
+ && (project->first("TEMPLATE") == "lib"
+ || project->first("TEMPLATE") == "vclib")
+ && !project->isActiveConfig("plugin")) { //write prl file
+ QString local_prl = prlFileName();
+ QString prl = fileFixify(local_prl);
+ mkdir(fileInfo(local_prl).path());
+ QFile ft(local_prl);
+ if(ft.open(QIODevice::WriteOnly)) {
+ project->values("ALL_DEPS").append(prl);
+ project->values("QMAKE_INTERNAL_PRL_FILE").append(prl);
+ QTextStream t(&ft);
+ writePrlFile(t);
+ }
+ }
+}
+
+// Manipulate directories, so it's possible to build
+// several cross-platform targets concurrently
+void
+MakefileGenerator::usePlatformDir()
+{
+ QString pltDir(project->first("QMAKE_PLATFORM_DIR"));
+ if(pltDir.isEmpty())
+ return;
+ QChar sep = QDir::separator();
+ QString slashPltDir = sep + pltDir;
+
+ QString dirs[] = { QString("OBJECTS_DIR"), QString("DESTDIR"), QString("QMAKE_PKGCONFIG_DESTDIR"),
+ QString("SUBLIBS_DIR"), QString("DLLDESTDIR"), QString("QMAKE_LIBTOOL_DESTDIR"),
+ QString("PRECOMPILED_DIR"), QString("QMAKE_LIBDIR_QT"), QString() };
+ for(int i = 0; !dirs[i].isEmpty(); ++i) {
+ QString filePath = project->first(dirs[i]);
+ project->values(dirs[i]) = QStringList(filePath + (filePath.isEmpty() ? pltDir : slashPltDir));
+ }
+
+ QString libs[] = { QString("QMAKE_LIBS_QT"), QString("QMAKE_LIBS_QT_THREAD"), QString("QMAKE_LIBS_QT_ENTRY"), QString() };
+ for(int i = 0; !libs[i].isEmpty(); ++i) {
+ QString filePath = project->first(libs[i]);
+ int fpi = filePath.lastIndexOf(sep);
+ if(fpi == -1)
+ project->values(libs[i]).prepend(pltDir + sep);
+ else
+ project->values(libs[i]) = QStringList(filePath.left(fpi) + slashPltDir + filePath.mid(fpi));
+ }
+}
+
+void
+MakefileGenerator::writeObj(QTextStream &t, const QString &src)
+{
+ QStringList &srcl = project->values(src);
+ QStringList objl = createObjectList(srcl);
+
+ QStringList::Iterator oit = objl.begin();
+ QStringList::Iterator sit = srcl.begin();
+ QString stringSrc("$src");
+ QString stringObj("$obj");
+ for(;sit != srcl.end() && oit != objl.end(); ++oit, ++sit) {
+ if((*sit).isEmpty())
+ continue;
+
+ t << escapeDependencyPath((*oit)) << ": " << escapeDependencyPath((*sit)) << " " << escapeDependencyPaths(findDependencies((*sit))).join(" \\\n\t\t");
+
+ QString comp, cimp;
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) {
+ if((*sit).endsWith((*cppit))) {
+ comp = "QMAKE_RUN_CXX";
+ cimp = "QMAKE_RUN_CXX_IMP";
+ break;
+ }
+ }
+ if(comp.isEmpty()) {
+ comp = "QMAKE_RUN_CC";
+ cimp = "QMAKE_RUN_CC_IMP";
+ }
+ bool use_implicit_rule = !project->isEmpty(cimp);
+ use_implicit_rule = false;
+ if(use_implicit_rule) {
+ if(!project->isEmpty("OBJECTS_DIR")) {
+ use_implicit_rule = false;
+ } else {
+ int dot = (*sit).lastIndexOf('.');
+ if(dot == -1 || ((*sit).left(dot) + Option::obj_ext != (*oit)))
+ use_implicit_rule = false;
+ }
+ }
+ if (!use_implicit_rule && !project->isEmpty(comp)) {
+ QString p = var(comp), srcf(*sit);
+ p.replace(stringSrc, escapeFilePath(srcf));
+ p.replace(stringObj, escapeFilePath((*oit)));
+ t << "\n\t" << p;
+ }
+ t << endl << endl;
+ }
+}
+
+QString
+MakefileGenerator::filePrefixRoot(const QString &root, const QString &path)
+{
+ QString ret(root + path);
+ if(path.length() > 2 && path[1] == ':') //c:\foo
+ ret = QString(path.mid(0, 2) + root + path.mid(2));
+ while(ret.endsWith("\\"))
+ ret = ret.left(ret.length()-1);
+ return ret;
+}
+
+void
+MakefileGenerator::writeInstalls(QTextStream &t, const QString &installs, bool noBuild)
+{
+ QString rm_dir_contents("-$(DEL_FILE)");
+ if (!isWindowsShell()) //ick
+ rm_dir_contents = "-$(DEL_FILE) -r";
+
+ QString all_installs, all_uninstalls;
+ QStringList &l = project->values(installs);
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString pvar = (*it) + ".path";
+ if(project->values((*it) + ".CONFIG").indexOf("no_path") == -1 &&
+ project->values((*it) + ".CONFIG").indexOf("dummy_install") == -1 &&
+ project->values(pvar).isEmpty()) {
+ warn_msg(WarnLogic, "%s is not defined: install target not created\n", pvar.toLatin1().constData());
+ continue;
+ }
+
+ bool do_default = true;
+ const QString root = "$(INSTALL_ROOT)";
+ QString target, dst;
+ if(project->values((*it) + ".CONFIG").indexOf("no_path") == -1 &&
+ project->values((*it) + ".CONFIG").indexOf("dummy_install") == -1) {
+ dst = fileFixify(unescapeFilePath(project->values(pvar).first()), FileFixifyAbsolute, false);
+ if(!dst.endsWith(Option::dir_sep))
+ dst += Option::dir_sep;
+ }
+ dst = escapeFilePath(dst);
+
+ QStringList tmp, uninst = project->values((*it) + ".uninstall");
+ //other
+ tmp = project->values((*it) + ".extra");
+ if(tmp.isEmpty())
+ tmp = project->values((*it) + ".commands"); //to allow compatible name
+ if(!tmp.isEmpty()) {
+ do_default = false;
+ if(!target.isEmpty())
+ target += "\n\t";
+ target += tmp.join(" ");
+ }
+ //masks
+ tmp = findFilesInVPATH(project->values((*it) + ".files"), VPATH_NoFixify);
+ tmp = fileFixify(tmp, FileFixifyAbsolute);
+ if(!tmp.isEmpty()) {
+ if(!target.isEmpty())
+ target += "\n";
+ do_default = false;
+ for(QStringList::Iterator wild_it = tmp.begin(); wild_it != tmp.end(); ++wild_it) {
+ QString wild = Option::fixPathToTargetOS((*wild_it), false, false);
+ QString dirstr = qmake_getpwd(), filestr = wild;
+ int slsh = filestr.lastIndexOf(Option::dir_sep);
+ if(slsh != -1) {
+ dirstr = filestr.left(slsh+1);
+ filestr.remove(0, slsh+1);
+ }
+ if(!dirstr.endsWith(Option::dir_sep))
+ dirstr += Option::dir_sep;
+ bool is_target = (wild == fileFixify(var("TARGET"), FileFixifyAbsolute));
+ if(is_target || exists(wild)) { //real file or target
+ QString file = wild;
+ QFileInfo fi(fileInfo(wild));
+ if(!target.isEmpty())
+ target += "\t";
+ QString dst_file = filePrefixRoot(root, dst);
+ if(fi.isDir() && project->isActiveConfig("copy_dir_files")) {
+ if(!dst_file.endsWith(Option::dir_sep))
+ dst_file += Option::dir_sep;
+ dst_file += fi.fileName();
+ }
+ QString cmd;
+ if (fi.isDir())
+ cmd = "-$(INSTALL_DIR)";
+ else if (is_target || fi.isExecutable())
+ cmd = "-$(INSTALL_PROGRAM)";
+ else
+ cmd = "-$(INSTALL_FILE)";
+ cmd += " " + escapeFilePath(wild) + " " + dst_file + "\n";
+ target += cmd;
+ if(!project->isActiveConfig("debug") && !project->isActiveConfig("nostrip") &&
+ !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP"))
+ target += QString("\t-") + var("QMAKE_STRIP") + " " +
+ filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false)) + "\n";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append(rm_dir_contents + " " + filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false)));
+ continue;
+ }
+ QString local_dirstr = Option::fixPathToLocalOS(dirstr, true);
+ QStringList files = QDir(local_dirstr).entryList(QStringList(filestr));
+ const QStringList &installConfigValues = project->values((*it) + ".CONFIG");
+ if (installConfigValues.contains("no_check_exist") && files.isEmpty()) {
+ if(!target.isEmpty())
+ target += "\t";
+ QString dst_file = filePrefixRoot(root, dst);
+ QFileInfo fi(fileInfo(wild));
+ QString cmd;
+ if (installConfigValues.contains("directory")) {
+ cmd = QLatin1String("-$(INSTALL_DIR)");
+ if (!dst_file.endsWith(Option::dir_sep))
+ dst_file += Option::dir_sep;
+ dst_file += fi.fileName();
+ } else if (installConfigValues.contains("executable")) {
+ cmd = QLatin1String("-$(INSTALL_PROGRAM)");
+ } else if (installConfigValues.contains("data")) {
+ cmd = QLatin1String("-$(INSTALL_FILE)");
+ } else {
+ cmd = QString(fi.isExecutable() ? "-$(INSTALL_PROGRAM)" : "-$(INSTALL_FILE)");
+ }
+ cmd += " " + wild + " " + dst_file + "\n";
+ target += cmd;
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append(rm_dir_contents + " " + filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false)));
+ }
+ for(int x = 0; x < files.count(); x++) {
+ QString file = files[x];
+ if(file == "." || file == "..") //blah
+ continue;
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append(rm_dir_contents + " " + filePrefixRoot(root, fileFixify(dst + file, FileFixifyAbsolute, false)));
+ QFileInfo fi(fileInfo(dirstr + file));
+ if(!target.isEmpty())
+ target += "\t";
+ QString dst_file = filePrefixRoot(root, fileFixify(dst, FileFixifyAbsolute, false));
+ if(fi.isDir() && project->isActiveConfig("copy_dir_files")) {
+ if(!dst_file.endsWith(Option::dir_sep))
+ dst_file += Option::dir_sep;
+ dst_file += fi.fileName();
+ }
+ QString cmd = QString(fi.isDir() ? "-$(INSTALL_DIR)" : "-$(INSTALL_FILE)") + " " +
+ dirstr + file + " " + dst_file + "\n";
+ target += cmd;
+ if(!project->isActiveConfig("debug") && !project->isActiveConfig("nostrip") &&
+ !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP"))
+ target += QString("\t-") + var("QMAKE_STRIP") + " " +
+ filePrefixRoot(root, fileFixify(dst + file, FileFixifyAbsolute, false)) +
+ "\n";
+ }
+ }
+ }
+ //default?
+ if(do_default) {
+ target = defaultInstall((*it));
+ uninst = project->values((*it) + ".uninstall");
+ }
+
+ if(!target.isEmpty() || project->values((*it) + ".CONFIG").indexOf("dummy_install") != -1) {
+ if(noBuild || project->values((*it) + ".CONFIG").indexOf("no_build") != -1)
+ t << "install_" << (*it) << ":";
+ else if(project->isActiveConfig("build_all"))
+ t << "install_" << (*it) << ": all";
+ else
+ t << "install_" << (*it) << ": first";
+ const QStringList &deps = project->values((*it) + ".depends");
+ if(!deps.isEmpty()) {
+ for(QStringList::ConstIterator dep_it = deps.begin(); dep_it != deps.end(); ++dep_it) {
+ QString targ = var((*dep_it) + ".target");
+ if(targ.isEmpty())
+ targ = (*dep_it);
+ t << " " << escapeDependencyPath(targ);
+ }
+ }
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\t";
+ const QStringList &dirs = project->values(pvar);
+ for(QStringList::ConstIterator pit = dirs.begin(); pit != dirs.end(); ++pit) {
+ QString tmp_dst = fileFixify((*pit), FileFixifyAbsolute, false);
+ if (!isWindowsShell() && !tmp_dst.endsWith(Option::dir_sep))
+ tmp_dst += Option::dir_sep;
+ t << mkdir_p_asstring(filePrefixRoot(root, tmp_dst)) << "\n\t";
+ }
+ t << target << endl << endl;
+ if(!uninst.isEmpty()) {
+ t << "uninstall_" << (*it) << ": ";
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\t"
+ << uninst.join(" ") << "\n\t"
+ << "-$(DEL_DIR) " << filePrefixRoot(root, dst) << " " << endl << endl;
+ }
+ t << endl;
+
+ if(project->values((*it) + ".CONFIG").indexOf("no_default_install") == -1) {
+ all_installs += QString("install_") + (*it) + " ";
+ if(!uninst.isEmpty())
+ all_uninstalls += "uninstall_" + (*it) + " ";
+ }
+ } else {
+ debug_msg(1, "no definition for install %s: install target not created",(*it).toLatin1().constData());
+ }
+ }
+ t << "install: " << var("INSTALLDEPS") << " " << all_installs;
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\n";
+ t << "uninstall: " << all_uninstalls << " " << var("UNINSTALLDEPS");
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\n";
+}
+
+QString
+MakefileGenerator::var(const QString &var)
+{
+ return val(project->values(var));
+}
+
+QString
+MakefileGenerator::val(const QStringList &varList)
+{
+ return valGlue(varList, "", " ", "");
+}
+
+QString
+MakefileGenerator::varGlue(const QString &var, const QString &before, const QString &glue, const QString &after)
+{
+ return valGlue(project->values(var), before, glue, after);
+}
+
+QString
+MakefileGenerator::valGlue(const QStringList &varList, const QString &before, const QString &glue, const QString &after)
+{
+ QString ret;
+ for(QStringList::ConstIterator it = varList.begin(); it != varList.end(); ++it) {
+ if(!(*it).isEmpty()) {
+ if(!ret.isEmpty())
+ ret += glue;
+ ret += (*it);
+ }
+ }
+ return ret.isEmpty() ? QString("") : before + ret + after;
+}
+
+
+QString
+MakefileGenerator::varList(const QString &var)
+{
+ return valList(project->values(var));
+}
+
+QString
+MakefileGenerator::valList(const QStringList &varList)
+{
+ return valGlue(varList, "", " \\\n\t\t", "");
+}
+
+QStringList
+MakefileGenerator::createObjectList(const QStringList &sources)
+{
+ QStringList ret;
+ QString objdir;
+ if(!project->values("OBJECTS_DIR").isEmpty())
+ objdir = project->first("OBJECTS_DIR");
+ for(QStringList::ConstIterator it = sources.begin(); it != sources.end(); ++it) {
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS((*it))));
+ QString dir;
+ if(objdir.isEmpty() && project->isActiveConfig("object_with_source")) {
+ QString fName = Option::fixPathToTargetOS((*it), false);
+ int dl = fName.lastIndexOf(Option::dir_sep);
+ if(dl != -1)
+ dir = fName.left(dl + 1);
+ } else {
+ dir = objdir;
+ }
+ ret.append(dir + fi.completeBaseName() + Option::obj_ext);
+ }
+ return ret;
+}
+
+ReplaceExtraCompilerCacheKey::ReplaceExtraCompilerCacheKey(const QString &v, const QStringList &i, const QStringList &o)
+{
+ static QString doubleColon = QLatin1String("::");
+
+ hash = 0;
+ pwd = qmake_getpwd();
+ var = v;
+ {
+ QStringList il = i;
+ il.sort();
+ in = il.join(doubleColon);
+ }
+ {
+ QStringList ol = o;
+ ol.sort();
+ out = ol.join(doubleColon);
+ }
+}
+
+bool ReplaceExtraCompilerCacheKey::operator==(const ReplaceExtraCompilerCacheKey &f) const
+{
+ return (hashCode() == f.hashCode() &&
+ f.in == in &&
+ f.out == out &&
+ f.var == var &&
+ f.pwd == pwd);
+}
+
+
+QString
+MakefileGenerator::replaceExtraCompilerVariables(const QString &orig_var, const QStringList &in, const QStringList &out)
+{
+ //lazy cache
+ ReplaceExtraCompilerCacheKey cacheKey(orig_var, in, out);
+ QString cacheVal = extraCompilerVariablesCache.value(cacheKey);
+ if(!cacheVal.isNull())
+ return cacheVal;
+
+ //do the work
+ QString ret = orig_var;
+ QRegExp reg_var("\\$\\{.*\\}");
+ reg_var.setMinimal(true);
+ for(int rep = 0; (rep = reg_var.indexIn(ret, rep)) != -1; ) {
+ QStringList val;
+ const QString var = ret.mid(rep + 2, reg_var.matchedLength() - 3);
+ bool filePath = false;
+ if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_VAR_"))) {
+ const QString varname = var.mid(10);
+ val += project->values(varname);
+ }
+ if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_VAR_FIRST_"))) {
+ const QString varname = var.mid(16);
+ val += project->first(varname);
+ }
+
+ if(val.isEmpty() && !in.isEmpty()) {
+ if(var.startsWith(QLatin1String("QMAKE_FUNC_FILE_IN_"))) {
+ filePath = true;
+ const QString funcname = var.mid(19);
+ val += project->expand(funcname, QList<QStringList>() << in);
+ } else if(var == QLatin1String("QMAKE_FILE_BASE") || var == QLatin1String("QMAKE_FILE_IN_BASE")) {
+ //filePath = true;
+ for(int i = 0; i < in.size(); ++i) {
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS(in.at(i))));
+ QString base = fi.completeBaseName();
+ if(base.isNull())
+ base = fi.fileName();
+ val += base;
+ }
+ } else if(var == QLatin1String("QMAKE_FILE_EXT")) {
+ filePath = true;
+ for(int i = 0; i < in.size(); ++i) {
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS(in.at(i))));
+ QString ext;
+ // Ensure complementarity with QMAKE_FILE_BASE
+ int baseLen = fi.completeBaseName().length();
+ if(baseLen == 0)
+ ext = fi.fileName();
+ else
+ ext = fi.fileName().remove(0, baseLen);
+ val += ext;
+ }
+ } else if(var == QLatin1String("QMAKE_FILE_PATH") || var == QLatin1String("QMAKE_FILE_IN_PATH")) {
+ filePath = true;
+ for(int i = 0; i < in.size(); ++i)
+ val += fileInfo(Option::fixPathToLocalOS(in.at(i))).path();
+ } else if(var == QLatin1String("QMAKE_FILE_NAME") || var == QLatin1String("QMAKE_FILE_IN")) {
+ filePath = true;
+ for(int i = 0; i < in.size(); ++i)
+ val += fileInfo(Option::fixPathToLocalOS(in.at(i))).filePath();
+
+ }
+ }
+ if(val.isEmpty() && !out.isEmpty()) {
+ if(var.startsWith(QLatin1String("QMAKE_FUNC_FILE_OUT_"))) {
+ filePath = true;
+ const QString funcname = var.mid(20);
+ val += project->expand(funcname, QList<QStringList>() << out);
+ } else if(var == QLatin1String("QMAKE_FILE_OUT")) {
+ filePath = true;
+ for(int i = 0; i < out.size(); ++i)
+ val += fileInfo(Option::fixPathToLocalOS(out.at(i))).filePath();
+ } else if(var == QLatin1String("QMAKE_FILE_OUT_BASE")) {
+ //filePath = true;
+ for(int i = 0; i < out.size(); ++i) {
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS(out.at(i))));
+ QString base = fi.completeBaseName();
+ if(base.isNull())
+ base = fi.fileName();
+ val += base;
+ }
+ }
+ }
+ if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_FUNC_"))) {
+ const QString funcname = var.mid(11);
+ val += project->expand(funcname, QList<QStringList>() << in << out);
+ }
+
+ if(!val.isEmpty()) {
+ QString fullVal;
+ if(filePath) {
+ for(int i = 0; i < val.size(); ++i) {
+ const QString file = Option::fixPathToTargetOS(unescapeFilePath(val.at(i)), false);
+ if(!fullVal.isEmpty())
+ fullVal += " ";
+ fullVal += escapeFilePath(file);
+ }
+ } else {
+ fullVal = val.join(" ");
+ }
+ ret.replace(rep, reg_var.matchedLength(), fullVal);
+ rep += fullVal.length();
+ } else {
+ rep += reg_var.matchedLength();
+ }
+ }
+
+ //cache the value
+ extraCompilerVariablesCache.insert(cacheKey, ret);
+ return ret;
+}
+
+bool
+MakefileGenerator::verifyExtraCompiler(const QString &comp, const QString &file_unfixed)
+{
+ if(noIO())
+ return false;
+ const QString file = Option::fixPathToLocalOS(file_unfixed);
+
+ if(project->values(comp + ".CONFIG").indexOf("moc_verify") != -1) {
+ if(!file.isNull()) {
+ QMakeSourceFileInfo::addSourceFile(file, QMakeSourceFileInfo::SEEK_MOCS);
+ if(!mocable(file)) {
+ return false;
+ } else {
+ project->values("MOCABLES").append(file);
+ }
+ }
+ } else if(project->values(comp + ".CONFIG").indexOf("function_verify") != -1) {
+ QString tmp_out = project->values(comp + ".output").first();
+ if(tmp_out.isEmpty())
+ return false;
+ QStringList verify_function = project->values(comp + ".verify_function");
+ if(verify_function.isEmpty())
+ return false;
+
+ for(int i = 0; i < verify_function.size(); ++i) {
+ bool invert = false;
+ QString verify = verify_function.at(i);
+ if(verify.at(0) == QLatin1Char('!')) {
+ invert = true;
+ verify = verify.mid(1);
+ }
+
+ if(project->values(comp + ".CONFIG").indexOf("combine") != -1) {
+ bool pass = project->test(verify, QList<QStringList>() << QStringList(tmp_out) << QStringList(file));
+ if(invert)
+ pass = !pass;
+ if(!pass)
+ return false;
+ } else {
+ QStringList &tmp = project->values(comp + ".input");
+ for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) {
+ QStringList &inputs = project->values((*it));
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
+ if((*input).isEmpty())
+ continue;
+ QString in = fileFixify(Option::fixPathToTargetOS((*input), false));
+ if(in == file) {
+ bool pass = project->test(verify,
+ QList<QStringList>() << QStringList(replaceExtraCompilerVariables(tmp_out, (*input), QString())) <<
+ QStringList(file));
+ if(invert)
+ pass = !pass;
+ if(!pass)
+ return false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ } else if(project->values(comp + ".CONFIG").indexOf("verify") != -1) {
+ QString tmp_out = project->values(comp + ".output").first();
+ if(tmp_out.isEmpty())
+ return false;
+ QString tmp_cmd;
+ if(!project->isEmpty(comp + ".commands")) {
+ int argv0 = -1;
+ QStringList cmdline = project->values(comp + ".commands");
+ for(int i = 0; i < cmdline.count(); ++i) {
+ if(!cmdline.at(i).contains('=')) {
+ argv0 = i;
+ break;
+ }
+ }
+ if(argv0 != -1) {
+ cmdline[argv0] = Option::fixPathToTargetOS(cmdline.at(argv0), false);
+ tmp_cmd = cmdline.join(" ");
+ }
+ }
+
+ if(project->values(comp + ".CONFIG").indexOf("combine") != -1) {
+ QString cmd = replaceExtraCompilerVariables(tmp_cmd, QString(), tmp_out);
+ if(system(cmd.toLatin1().constData()))
+ return false;
+ } else {
+ QStringList &tmp = project->values(comp + ".input");
+ for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) {
+ QStringList &inputs = project->values((*it));
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
+ if((*input).isEmpty())
+ continue;
+ QString in = fileFixify(Option::fixPathToTargetOS((*input), false));
+ if(in == file) {
+ QString out = replaceExtraCompilerVariables(tmp_out, (*input), QString());
+ QString cmd = replaceExtraCompilerVariables(tmp_cmd, in, out);
+ if(system(cmd.toLatin1().constData()))
+ return false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void
+MakefileGenerator::writeExtraTargets(QTextStream &t)
+{
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::Iterator it = qut.begin(); it != qut.end(); ++it) {
+ QString targ = var((*it) + ".target"),
+ cmd = var((*it) + ".commands"), deps;
+ if(targ.isEmpty())
+ targ = (*it);
+ QStringList &deplist = project->values((*it) + ".depends");
+ for(QStringList::Iterator dep_it = deplist.begin(); dep_it != deplist.end(); ++dep_it) {
+ QString dep = var((*dep_it) + ".target");
+ if(dep.isEmpty())
+ dep = (*dep_it);
+ deps += " " + escapeDependencyPath(dep);
+ }
+ if(project->values((*it) + ".CONFIG").indexOf("fix_target") != -1)
+ targ = fileFixify(targ, Option::output_dir, Option::output_dir);
+ if(project->isEmpty("QMAKE_NOFORCE") &&
+ project->values((*it) + ".CONFIG").indexOf("phony") != -1)
+ deps += QString(" ") + "FORCE";
+ t << escapeDependencyPath(targ) << ":" << deps;
+ if(!cmd.isEmpty())
+ t << "\n\t" << cmd;
+ t << endl << endl;
+
+ project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(targ);
+ project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(targ)) << deps.split(" ", QString::SkipEmptyParts);
+ project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(targ)) << cmd;
+ }
+}
+
+void
+MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
+{
+ QString clean_targets;
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = fileFixify(project->values((*it) + ".output").first(),
+ Option::output_dir, Option::output_dir);
+ QString tmp_cmd;
+ if(!project->isEmpty((*it) + ".commands")) {
+ QStringList cmdline = project->values((*it) + ".commands");
+ int argv0 = findExecutable(cmdline);
+ if(argv0 != -1) {
+ cmdline[argv0] = escapeFilePath(Option::fixPathToTargetOS(cmdline.at(argv0), false));
+ tmp_cmd = cmdline.join(" ");
+ }
+ }
+ QStringList tmp_dep = project->values((*it) + ".depends");
+ QString tmp_dep_cmd;
+ QString dep_cd_cmd;
+ if(!project->isEmpty((*it) + ".depend_command")) {
+ int argv0 = -1;
+ QStringList cmdline = project->values((*it) + ".depend_command");
+ for(int i = 0; i < cmdline.count(); ++i) {
+ if(!cmdline.at(i).contains('=')) {
+ argv0 = i;
+ break;
+ }
+ }
+ if(argv0 != -1) {
+ const QString c = Option::fixPathToLocalOS(cmdline.at(argv0), true);
+ if(exists(c)) {
+ cmdline[argv0] = escapeFilePath(Option::fixPathToLocalOS(cmdline.at(argv0), false));
+ } else {
+ cmdline[argv0] = escapeFilePath(cmdline.at(argv0));
+ }
+ QFileInfo cmdFileInfo(cmdline[argv0]);
+ if (!cmdFileInfo.isAbsolute() || cmdFileInfo.exists())
+ tmp_dep_cmd = cmdline.join(" ");
+ }
+ dep_cd_cmd = QLatin1String("cd ")
+ + escapeFilePath(Option::fixPathToLocalOS(Option::output_dir, false))
+ + QLatin1String(" && ");
+ }
+ QStringList &vars = project->values((*it) + ".variables");
+ if(tmp_out.isEmpty() || tmp_cmd.isEmpty())
+ continue;
+ QStringList tmp_inputs;
+ {
+ const QStringList &comp_inputs = project->values((*it) + ".input");
+ for(QStringList::ConstIterator it2 = comp_inputs.begin(); it2 != comp_inputs.end(); ++it2) {
+ const QStringList &tmp = project->values((*it2));
+ for(QStringList::ConstIterator input = tmp.begin(); input != tmp.end(); ++input) {
+ QString in = Option::fixPathToTargetOS((*input), false);
+ if(verifyExtraCompiler((*it), in))
+ tmp_inputs.append((*input));
+ }
+ }
+ }
+
+ t << "compiler_" << (*it) << "_make_all:";
+ if(project->values((*it) + ".CONFIG").indexOf("combine") != -1) {
+ // compilers with a combined input only have one output
+ QString input = project->values((*it) + ".output").first();
+ t << " " << escapeDependencyPath(replaceExtraCompilerVariables(tmp_out, input, QString()));
+ } else {
+ for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) {
+ QString in = Option::fixPathToTargetOS((*input), false);
+ t << " " << escapeDependencyPath(replaceExtraCompilerVariables(tmp_out, (*input), QString()));
+ }
+ }
+ t << endl;
+
+ if(project->values((*it) + ".CONFIG").indexOf("no_clean") == -1) {
+ QString tmp_clean = project->values((*it) + ".clean").join(" ");
+ QString tmp_clean_cmds = project->values((*it) + ".clean_commands").join(" ");
+ if(!tmp_inputs.isEmpty())
+ clean_targets += QString("compiler_" + (*it) + "_clean ");
+ t << "compiler_" << (*it) << "_clean:";
+ bool wrote_clean_cmds = false, wrote_clean = false;
+ if(tmp_clean_cmds.isEmpty()) {
+ wrote_clean_cmds = true;
+ } else if(tmp_clean_cmds.indexOf("${QMAKE_") == -1) {
+ t << "\n\t" << tmp_clean_cmds;
+ wrote_clean_cmds = true;
+ }
+ if(tmp_clean.isEmpty())
+ tmp_clean = tmp_out;
+ if(tmp_clean.indexOf("${QMAKE_") == -1) {
+ t << "\n\t" << "-$(DEL_FILE) " << tmp_clean;
+ wrote_clean = true;
+ }
+ if(!wrote_clean_cmds || !wrote_clean) {
+ QStringList cleans;
+ const QString del_statement("-$(DEL_FILE)");
+ if(!wrote_clean) {
+ if(project->isActiveConfig("no_delete_multiple_files")) {
+ for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input)
+ cleans.append(" " + replaceExtraCompilerVariables(tmp_clean, (*input),
+ replaceExtraCompilerVariables(tmp_out, (*input), QString())));
+ } else {
+ QString files, file;
+ const int commandlineLimit = 2047; // NT limit, expanded
+ for(int input = 0; input < tmp_inputs.size(); ++input) {
+ file = " " + replaceExtraCompilerVariables(tmp_clean, tmp_inputs.at(input),
+ replaceExtraCompilerVariables(tmp_out, tmp_inputs.at(input), QString()));
+ if(del_statement.length() + files.length() +
+ qMax(fixEnvVariables(file).length(), file.length()) > commandlineLimit) {
+ cleans.append(files);
+ files.clear();
+ }
+ files += file;
+ }
+ if(!files.isEmpty())
+ cleans.append(files);
+ }
+ }
+ if(!cleans.isEmpty())
+ t << valGlue(cleans, "\n\t" + del_statement, "\n\t" + del_statement, "");
+ if(!wrote_clean_cmds) {
+ for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) {
+ t << "\n\t" << replaceExtraCompilerVariables(tmp_clean_cmds, (*input),
+ replaceExtraCompilerVariables(tmp_out, (*input), QString()));
+ }
+ }
+ }
+ t << endl;
+ }
+ if(project->values((*it) + ".CONFIG").indexOf("combine") != -1) {
+ if(tmp_out.indexOf("${QMAKE_") != -1) {
+ warn_msg(WarnLogic, "QMAKE_EXTRA_COMPILERS(%s) with combine has variable output.",
+ (*it).toLatin1().constData());
+ continue;
+ }
+ QStringList deps, inputs;
+ if(!tmp_dep.isEmpty())
+ deps += fileFixify(tmp_dep, Option::output_dir, Option::output_dir);
+ for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) {
+ deps += findDependencies((*input));
+ inputs += Option::fixPathToTargetOS((*input), false);
+ if(!tmp_dep_cmd.isEmpty() && doDepends()) {
+ char buff[256];
+ QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, (*input),
+ tmp_out);
+ dep_cmd = dep_cd_cmd + fixEnvVariables(dep_cmd);
+ if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) {
+ QString indeps;
+ while(!feof(proc)) {
+ int read_in = (int)fread(buff, 1, 255, proc);
+ if(!read_in)
+ break;
+ indeps += QByteArray(buff, read_in);
+ }
+ QT_PCLOSE(proc);
+ if(!indeps.isEmpty()) {
+ QStringList dep_cmd_deps = indeps.replace('\n', ' ').simplified().split(' ');
+ for(int i = 0; i < dep_cmd_deps.count(); ++i) {
+ QString &file = dep_cmd_deps[i];
+ if(!exists(file)) {
+ QString localFile;
+ QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths();
+ for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin();
+ it != depdirs.end(); ++it) {
+ if(exists((*it).real() + Option::dir_sep + file)) {
+ localFile = (*it).local() + Option::dir_sep + file;
+ break;
+ }
+ }
+ file = localFile;
+ }
+ if(!file.isEmpty())
+ file = fileFixify(file);
+ }
+ deps += dep_cmd_deps;
+ }
+ }
+ }
+ }
+ for(int i = 0; i < inputs.size(); ) {
+ if(tmp_out == inputs.at(i))
+ inputs.removeAt(i);
+ else
+ ++i;
+ }
+ for(int i = 0; i < deps.size(); ) {
+ if(tmp_out == deps.at(i))
+ deps.removeAt(i);
+ else
+ ++i;
+ }
+ if (inputs.isEmpty())
+ continue;
+
+ QString cmd;
+ if (isForSymbianSbsv2()) {
+ // In sbsv2 the command inputs and outputs need to use absolute paths
+ cmd = replaceExtraCompilerVariables(tmp_cmd,
+ fileFixify(escapeFilePaths(inputs), FileFixifyAbsolute),
+ fileFixify(QStringList(tmp_out), FileFixifyAbsolute));
+ } else {
+ cmd = replaceExtraCompilerVariables(tmp_cmd, escapeFilePaths(inputs), QStringList(tmp_out));
+ }
+
+ t << escapeDependencyPath(tmp_out) << ":";
+ project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(tmp_out);
+ // compiler.CONFIG+=explicit_dependencies means that ONLY compiler.depends gets to cause Makefile dependencies
+ if(project->values((*it) + ".CONFIG").indexOf("explicit_dependencies") != -1) {
+ t << " " << valList(escapeDependencyPaths(fileFixify(tmp_dep, Option::output_dir, Option::output_dir)));
+ project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(tmp_out)) << tmp_dep;
+ } else {
+ t << " " << valList(escapeDependencyPaths(inputs)) << " " << valList(escapeDependencyPaths(deps));
+ project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(tmp_out)) << inputs << deps;
+ }
+ t << "\n\t" << cmd << endl << endl;
+ project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(tmp_out)) << cmd;
+ continue;
+ }
+ for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) {
+ QString in = Option::fixPathToTargetOS((*input), false);
+ QStringList deps = findDependencies((*input));
+ deps += escapeDependencyPath(in);
+ QString out = replaceExtraCompilerVariables(tmp_out, (*input), QString());
+ if(!tmp_dep.isEmpty()) {
+ QStringList pre_deps = fileFixify(tmp_dep, Option::output_dir, Option::output_dir);
+ for(int i = 0; i < pre_deps.size(); ++i)
+ deps += replaceExtraCompilerVariables(pre_deps.at(i), (*input), out);
+ }
+ QString cmd = replaceExtraCompilerVariables(tmp_cmd, (*input), out);
+ // NOTE: The var -> QMAKE_COMP_var replace feature is unsupported, do not use!
+ if (isForSymbianSbsv2()) {
+ // In sbsv2 the command inputs and outputs need to use absolute paths
+ cmd = replaceExtraCompilerVariables(tmp_cmd,
+ fileFixify((*input), FileFixifyAbsolute),
+ fileFixify(out, FileFixifyAbsolute));
+ } else {
+ cmd = replaceExtraCompilerVariables(tmp_cmd, (*input), out);
+ }
+ for(QStringList::ConstIterator it3 = vars.constBegin(); it3 != vars.constEnd(); ++it3)
+ cmd.replace("$(" + (*it3) + ")", "$(QMAKE_COMP_" + (*it3)+")");
+ if(!tmp_dep_cmd.isEmpty() && doDepends()) {
+ char buff[256];
+ QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, (*input), out);
+ dep_cmd = dep_cd_cmd + fixEnvVariables(dep_cmd);
+ if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) {
+ QString indeps;
+ while(!feof(proc)) {
+ int read_in = (int)fread(buff, 1, 255, proc);
+ if(!read_in)
+ break;
+ indeps += QByteArray(buff, read_in);
+ }
+ QT_PCLOSE(proc);
+ if(!indeps.isEmpty()) {
+ QStringList dep_cmd_deps = indeps.replace('\n', ' ').simplified().split(' ');
+ for(int i = 0; i < dep_cmd_deps.count(); ++i) {
+ QString &file = dep_cmd_deps[i];
+ if(!exists(file)) {
+ QString localFile;
+ QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths();
+ for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin();
+ it != depdirs.end(); ++it) {
+ if(exists((*it).real() + Option::dir_sep + file)) {
+ localFile = (*it).local() + Option::dir_sep + file;
+ break;
+ }
+ }
+ file = localFile;
+ }
+ if(!file.isEmpty())
+ file = fileFixify(file);
+ }
+ deps += dep_cmd_deps;
+ }
+ }
+ //use the depend system to find includes of these included files
+ QStringList inc_deps;
+ for(int i = 0; i < deps.size(); ++i) {
+ const QString dep = deps.at(i);
+ if(QFile::exists(dep)) {
+ SourceFileType type = TYPE_UNKNOWN;
+ if(type == TYPE_UNKNOWN) {
+ for(QStringList::Iterator cit = Option::c_ext.begin();
+ cit != Option::c_ext.end(); ++cit) {
+ if(dep.endsWith((*cit))) {
+ type = TYPE_C;
+ break;
+ }
+ }
+ }
+ if(type == TYPE_UNKNOWN) {
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin();
+ cppit != Option::cpp_ext.end(); ++cppit) {
+ if(dep.endsWith((*cppit))) {
+ type = TYPE_C;
+ break;
+ }
+ }
+ }
+ if(type == TYPE_UNKNOWN) {
+ for(QStringList::Iterator hit = Option::h_ext.begin();
+ type == TYPE_UNKNOWN && hit != Option::h_ext.end(); ++hit) {
+ if(dep.endsWith((*hit))) {
+ type = TYPE_C;
+ break;
+ }
+ }
+ }
+ if(type != TYPE_UNKNOWN) {
+ if(!QMakeSourceFileInfo::containsSourceFile(dep, type))
+ QMakeSourceFileInfo::addSourceFile(dep, type);
+ inc_deps += QMakeSourceFileInfo::dependencies(dep);
+ }
+ }
+ }
+ deps += inc_deps;
+ }
+ for(int i = 0; i < deps.size(); ) {
+ QString &dep = deps[i];
+ dep = Option::fixPathToTargetOS(unescapeFilePath(dep), false);
+ if(out == dep)
+ deps.removeAt(i);
+ else
+ ++i;
+ }
+ t << escapeDependencyPath(out) << ": " << valList(escapeDependencyPaths(deps)) << "\n\t"
+ << cmd << endl << endl;
+ project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(out);
+ project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(out)) << deps;
+ project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(out)) << cmd;
+ }
+ }
+ t << "compiler_clean: " << clean_targets << endl << endl;
+}
+
+void
+MakefileGenerator::writeExtraCompilerVariables(QTextStream &t)
+{
+ bool first = true;
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const QStringList &vars = project->values((*it) + ".variables");
+ for(QStringList::ConstIterator varit = vars.begin(); varit != vars.end(); ++varit) {
+ if(first) {
+ t << "\n####### Custom Compiler Variables" << endl;
+ first = false;
+ }
+ t << "QMAKE_COMP_" << (*varit) << " = "
+ << valList(project->values((*varit))) << endl;
+ }
+ }
+ if(!first)
+ t << endl;
+}
+
+void
+MakefileGenerator::writeExtraVariables(QTextStream &t)
+{
+ bool first = true;
+ QMap<QString, QStringList> &vars = project->variables();
+ QStringList &exports = project->values("QMAKE_EXTRA_VARIABLES");
+ for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) {
+ for(QStringList::Iterator exp_it = exports.begin(); exp_it != exports.end(); ++exp_it) {
+ QRegExp rx((*exp_it), Qt::CaseInsensitive, QRegExp::Wildcard);
+ if(rx.exactMatch(it.key())) {
+ if(first) {
+ t << "\n####### Custom Variables" << endl;
+ first = false;
+ }
+ t << "EXPORT_" << it.key() << " = " << it.value().join(" ") << endl;
+ }
+ }
+ }
+ if(!first)
+ t << endl;
+}
+
+bool
+MakefileGenerator::writeStubMakefile(QTextStream &t)
+{
+ t << "QMAKE = " << var("QMAKE_QMAKE") << endl;
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
+ t << *it << " ";
+ //const QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ t << "first all clean install distclean uninstall: " << "qmake" << endl
+ << "qmake_all:" << endl;
+ writeMakeQmake(t);
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << "FORCE:" << endl << endl;
+ return true;
+}
+
+bool
+MakefileGenerator::writeMakefile(QTextStream &t)
+{
+ t << "####### Compile" << endl << endl;
+ writeObj(t, "SOURCES");
+ writeObj(t, "GENERATED_SOURCES");
+
+ t << "####### Install" << endl << endl;
+ writeInstalls(t, "INSTALLS");
+
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << "FORCE:" << endl << endl;
+ return true;
+}
+
+QString MakefileGenerator::buildArgs(const QString &outdir)
+{
+ QString ret;
+ //special variables
+ if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
+ ret += " QMAKE_ABSOLUTE_SOURCE_PATH=" + escapeFilePath(project->first("QMAKE_ABSOLUTE_SOURCE_PATH"));
+
+ //warnings
+ else if(Option::warn_level == WarnNone)
+ ret += " -Wnone";
+ else if(Option::warn_level == WarnAll)
+ ret += " -Wall";
+ else if(Option::warn_level & WarnParser)
+ ret += " -Wparser";
+ //other options
+ if(!Option::user_template.isEmpty())
+ ret += " -t " + Option::user_template;
+ if(!Option::user_template_prefix.isEmpty())
+ ret += " -tp " + Option::user_template_prefix;
+ if(!Option::mkfile::do_cache)
+ ret += " -nocache";
+ if(!Option::mkfile::do_deps)
+ ret += " -nodepend";
+ if(!Option::mkfile::do_dep_heuristics)
+ ret += " -nodependheuristics";
+ if(!Option::mkfile::qmakespec_commandline.isEmpty())
+ ret += " -spec " + specdir(outdir);
+ if (Option::target_mode_overridden) {
+ if (Option::target_mode == Option::TARG_MACX_MODE)
+ ret += " -macx";
+ else if (Option::target_mode == Option::TARG_UNIX_MODE)
+ ret += " -unix";
+ else if (Option::target_mode == Option::TARG_WIN_MODE)
+ ret += " -win32";
+ }
+
+ //configs
+ for(QStringList::Iterator it = Option::user_configs.begin();
+ it != Option::user_configs.end(); ++it)
+ ret += " -config " + (*it);
+ //arguments
+ for(QStringList::Iterator it = Option::before_user_vars.begin();
+ it != Option::before_user_vars.end(); ++it) {
+ if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH")
+ ret += " " + escapeFilePath((*it));
+ }
+ if(Option::after_user_vars.count()) {
+ ret += " -after ";
+ for(QStringList::Iterator it = Option::after_user_vars.begin();
+ it != Option::after_user_vars.end(); ++it) {
+ if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH")
+ ret += " " + escapeFilePath((*it));
+ }
+ }
+ return ret;
+}
+
+//could get stored argv, but then it would have more options than are
+//probably necesary this will try to guess the bare minimum..
+QString MakefileGenerator::build_args(const QString &outdir)
+{
+ QString ret = "$(QMAKE)";
+
+ // general options and arguments
+ ret += buildArgs(outdir);
+
+ //output
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(!ofile.isEmpty() && ofile != project->first("QMAKE_MAKEFILE"))
+ ret += " -o " + escapeFilePath(ofile);
+
+ //inputs
+ ret += " " + escapeFilePath(fileFixify(project->projectFile(), outdir));
+
+ return ret;
+}
+
+void
+MakefileGenerator::writeHeader(QTextStream &t)
+{
+ t << "#############################################################################" << endl;
+ t << "# Makefile for building: " << escapeFilePath(var("TARGET")) << endl;
+ t << "# Generated by qmake (" << qmake_version() << ") (Qt " << QT_VERSION_STR << ") on: ";
+ t << QDateTime::currentDateTime().toString() << endl;
+ t << "# Project: " << fileFixify(project->projectFile()) << endl;
+ t << "# Template: " << var("TEMPLATE") << endl;
+ if(!project->isActiveConfig("build_pass"))
+ t << "# Command: " << build_args().replace("$(QMAKE)", var("QMAKE_QMAKE")) << endl;
+ t << "#############################################################################" << endl;
+ t << endl;
+}
+
+QList<MakefileGenerator::SubTarget*>
+MakefileGenerator::findSubDirsSubTargets() const
+{
+ QList<SubTarget*> targets;
+ {
+ const QStringList subdirs = project->values("SUBDIRS");
+ for(int subdir = 0; subdir < subdirs.size(); ++subdir) {
+ QString fixedSubdir = subdirs[subdir];
+ fixedSubdir = fixedSubdir.replace(QRegExp("[^a-zA-Z0-9_]"),"-");
+
+ SubTarget *st = new SubTarget;
+ st->name = subdirs[subdir];
+ targets.append(st);
+
+ bool fromFile = false;
+ QString file = subdirs[subdir];
+ if(!project->isEmpty(fixedSubdir + ".file")) {
+ if(!project->isEmpty(fixedSubdir + ".subdir"))
+ warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s",
+ subdirs[subdir].toLatin1().constData());
+ file = project->first(fixedSubdir + ".file");
+ fromFile = true;
+ } else if(!project->isEmpty(fixedSubdir + ".subdir")) {
+ file = project->first(fixedSubdir + ".subdir");
+ fromFile = false;
+ } else {
+ fromFile = file.endsWith(Option::pro_ext);
+ }
+ file = Option::fixPathToTargetOS(file);
+
+ if(fromFile) {
+ int slsh = file.lastIndexOf(Option::dir_sep);
+ if(slsh != -1) {
+ st->in_directory = file.left(slsh+1);
+ st->profile = file.mid(slsh+1);
+ } else {
+ st->profile = file;
+ }
+ } else {
+ if(!file.isEmpty() && !project->isActiveConfig("subdir_first_pro"))
+ st->profile = file.section(Option::dir_sep, -1) + Option::pro_ext;
+ st->in_directory = file;
+ }
+ while(st->in_directory.endsWith(Option::dir_sep))
+ st->in_directory.chop(1);
+ if(fileInfo(st->in_directory).isRelative())
+ st->out_directory = st->in_directory;
+ else
+ st->out_directory = fileFixify(st->in_directory, qmake_getpwd(), Option::output_dir);
+ if(!project->isEmpty(fixedSubdir + ".makefile")) {
+ st->makefile = project->first(fixedSubdir + ".makefile");
+ } else {
+ st->makefile = "$(MAKEFILE)";
+ if(!st->profile.isEmpty()) {
+ QString basename = st->in_directory;
+ int new_slsh = basename.lastIndexOf(Option::dir_sep);
+ if(new_slsh != -1)
+ basename = basename.mid(new_slsh+1);
+ if(st->profile != basename + Option::pro_ext)
+ st->makefile += "." + st->profile.left(st->profile.length() - Option::pro_ext.length());
+ }
+ }
+ if(!project->isEmpty(fixedSubdir + ".depends")) {
+ const QStringList depends = project->values(fixedSubdir + ".depends");
+ for(int depend = 0; depend < depends.size(); ++depend) {
+ bool found = false;
+ for(int subDep = 0; subDep < subdirs.size(); ++subDep) {
+ if(subdirs[subDep] == depends.at(depend)) {
+ QString fixedSubDep = subdirs[subDep];
+ fixedSubDep = fixedSubDep.replace(QRegExp("[^a-zA-Z0-9_]"),"-");
+ if(!project->isEmpty(fixedSubDep + ".target")) {
+ st->depends += project->first(fixedSubDep + ".target");
+ } else {
+ QString d = Option::fixPathToLocalOS(subdirs[subDep]);
+ if(!project->isEmpty(fixedSubDep + ".file"))
+ d = project->first(fixedSubDep + ".file");
+ else if(!project->isEmpty(fixedSubDep + ".subdir"))
+ d = project->first(fixedSubDep + ".subdir");
+ st->depends += "sub-" + d.replace(QRegExp("[^a-zA-Z0-9_]"),"-");
+ }
+ found = true;
+ break;
+ }
+ }
+ if(!found) {
+ QString depend_str = depends.at(depend);
+ st->depends += depend_str.replace(QRegExp("[^a-zA-Z0-9_]"),"-");
+ }
+ }
+ }
+ if(!project->isEmpty(fixedSubdir + ".target")) {
+ st->target = project->first(fixedSubdir + ".target");
+ } else {
+ st->target = "sub-" + file;
+ st->target = st->target.replace(QRegExp("[^a-zA-Z0-9_]"),"-");
+ }
+ }
+ }
+ return targets;
+}
+
+void
+MakefileGenerator::writeSubDirs(QTextStream &t)
+{
+ QList<SubTarget*> targets = findSubDirsSubTargets();
+ t << "first: make_default" << endl;
+ int flags = SubTargetInstalls;
+ if(project->isActiveConfig("ordered"))
+ flags |= SubTargetOrdered;
+ writeSubTargets(t, targets, flags);
+ qDeleteAll(targets);
+}
+
+void
+MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubTarget*> targets, int flags)
+{
+ // blasted includes
+ QStringList &qeui = project->values("QMAKE_EXTRA_INCLUDES");
+ for(QStringList::Iterator qeui_it = qeui.begin(); qeui_it != qeui.end(); ++qeui_it)
+ t << "include " << (*qeui_it) << endl;
+
+ if (!(flags & SubTargetSkipDefaultVariables)) {
+ QString ofile = Option::fixPathToTargetOS(Option::output.fileName());
+ if(ofile.lastIndexOf(Option::dir_sep) != -1)
+ ofile.remove(0, ofile.lastIndexOf(Option::dir_sep) +1);
+ t << "MAKEFILE = " << ofile << endl;
+ /* Calling Option::fixPathToTargetOS() is necessary for MinGW/MSYS, which requires
+ * back-slashes to be turned into slashes. */
+ t << "QMAKE = " << var("QMAKE_QMAKE") << endl;
+ t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ t << "CHK_DIR_EXISTS= " << var("QMAKE_CHK_DIR_EXISTS") << endl;
+ t << "MKDIR = " << var("QMAKE_MKDIR") << endl;
+ t << "COPY = " << var("QMAKE_COPY") << endl;
+ t << "COPY_FILE = " << var("QMAKE_COPY_FILE") << endl;
+ t << "COPY_DIR = " << var("QMAKE_COPY_DIR") << endl;
+ t << "INSTALL_FILE = " << var("QMAKE_INSTALL_FILE") << endl;
+ t << "INSTALL_PROGRAM = " << var("QMAKE_INSTALL_PROGRAM") << endl;
+ t << "INSTALL_DIR = " << var("QMAKE_INSTALL_DIR") << endl;
+ t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ t << "SYMLINK = " << var("QMAKE_SYMBOLIC_LINK") << endl;
+ t << "DEL_DIR = " << var("QMAKE_DEL_DIR") << endl;
+ t << "MOVE = " << var("QMAKE_MOVE") << endl;
+ t << "CHK_DIR_EXISTS= " << var("QMAKE_CHK_DIR_EXISTS") << endl;
+ t << "MKDIR = " << var("QMAKE_MKDIR") << endl;
+ t << "SUBTARGETS = "; // subtargets are sub-directory
+ for(int target = 0; target < targets.size(); ++target)
+ t << " \\\n\t\t" << targets.at(target)->target;
+ t << endl << endl;
+ }
+ writeExtraVariables(t);
+
+ QStringList targetSuffixes;
+ const QString abs_source_path = project->first("QMAKE_ABSOLUTE_SOURCE_PATH");
+ if (!(flags & SubTargetSkipDefaultTargets)) {
+ targetSuffixes << "make_default" << "make_first" << "all" << "clean" << "distclean"
+ << QString((flags & SubTargetInstalls) ? "install_subtargets" : "install")
+ << QString((flags & SubTargetInstalls) ? "uninstall_subtargets" : "uninstall");
+ }
+
+ // generate target rules
+ for(int target = 0; target < targets.size(); ++target) {
+ SubTarget *subtarget = targets.at(target);
+ QString in_directory = subtarget->in_directory;
+ if(!in_directory.isEmpty() && !in_directory.endsWith(Option::dir_sep))
+ in_directory += Option::dir_sep;
+ QString out_directory = subtarget->out_directory;
+ if(!out_directory.isEmpty() && !out_directory.endsWith(Option::dir_sep))
+ out_directory += Option::dir_sep;
+ if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path))
+ out_directory = Option::output_dir + out_directory.mid(abs_source_path.length());
+
+ QString mkfile = subtarget->makefile;
+ if(!in_directory.isEmpty())
+ mkfile.prepend(out_directory);
+
+ QString in_directory_cdin, in_directory_cdout, out_directory_cdin, out_directory_cdout;
+#define MAKE_CD_IN_AND_OUT(directory) \
+ if(!directory.isEmpty()) { \
+ if(project->isActiveConfig("cd_change_global")) { \
+ directory ## _cdin = "\n\tcd " + directory + "\n\t"; \
+ QDir pwd(Option::output_dir); \
+ QStringList in = directory.split(Option::dir_sep), out; \
+ for(int i = 0; i < in.size(); i++) { \
+ if(in.at(i) == "..") \
+ out.prepend(fileInfo(pwd.path()).fileName()); \
+ else if(in.at(i) != ".") \
+ out.prepend(".."); \
+ pwd.cd(in.at(i)); \
+ } \
+ directory ## _cdout = "\n\t@cd " + out.join(Option::dir_sep); \
+ } else { \
+ directory ## _cdin = "\n\tcd " + directory + " && "; \
+ } \
+ } else { \
+ directory ## _cdin = "\n\t"; \
+ }
+ MAKE_CD_IN_AND_OUT(in_directory);
+ MAKE_CD_IN_AND_OUT(out_directory);
+
+ //qmake it
+ if(!subtarget->profile.isEmpty()) {
+ QString out = subtarget->makefile;
+ QString in = fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute);
+ if(out.startsWith(in_directory))
+ out = out.mid(in_directory.length());
+ t << mkfile << ": " << "\n\t";
+ if(!in_directory.isEmpty()) {
+ t << mkdir_p_asstring(out_directory)
+ << out_directory_cdin
+ << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out
+ << in_directory_cdout << endl;
+ } else {
+ t << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out << endl;
+ }
+ t << subtarget->target << "-qmake_all: ";
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\t";
+ if(!in_directory.isEmpty()) {
+ t << mkdir_p_asstring(out_directory)
+ << out_directory_cdin
+ << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out
+ << in_directory_cdout << endl;
+ } else {
+ t << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out << endl;
+ }
+ }
+
+ QString makefilein = " -f " + subtarget->makefile;
+
+ { //actually compile
+ t << subtarget->target << ": " << mkfile;
+ if(!subtarget->depends.isEmpty())
+ t << " " << valList(subtarget->depends);
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << out_directory_cdin
+ << "$(MAKE)" << makefilein
+ << out_directory_cdout << endl;
+ }
+
+ for(int suffix = 0; suffix < targetSuffixes.size(); ++suffix) {
+ QString s = targetSuffixes.at(suffix);
+ if(s == "install_subtargets")
+ s = "install";
+ else if(s == "uninstall_subtargets")
+ s = "uninstall";
+ else if(s == "make_first")
+ s = "first";
+ else if(s == "make_default")
+ s = QString();
+
+ if(flags & SubTargetOrdered) {
+ t << subtarget->target << "-" << targetSuffixes.at(suffix) << "-ordered: " << mkfile;
+ if(target)
+ t << " " << targets.at(target-1)->target << "-" << targetSuffixes.at(suffix) << "-ordered ";
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << out_directory_cdin
+ << "$(MAKE)" << makefilein << " " << s
+ << out_directory_cdout << endl;
+ }
+ t << subtarget->target << "-" << targetSuffixes.at(suffix) << ": " << mkfile;
+ if(!subtarget->depends.isEmpty())
+ t << " " << valGlue(subtarget->depends, QString(), "-" + targetSuffixes.at(suffix) + " ",
+ "-"+targetSuffixes.at(suffix));
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << out_directory_cdin
+ << "$(MAKE)" << makefilein << " " << s
+ << out_directory_cdout << endl;
+ }
+ }
+ t << endl;
+
+ if (!(flags & SubTargetSkipDefaultTargets)) {
+ if(project->values("QMAKE_INTERNAL_QMAKE_DEPS").indexOf("qmake_all") == -1)
+ project->values("QMAKE_INTERNAL_QMAKE_DEPS").append("qmake_all");
+
+ writeMakeQmake(t);
+
+ t << "qmake_all:";
+ if(!targets.isEmpty()) {
+ for(QList<SubTarget*>::Iterator it = targets.begin(); it != targets.end(); ++it) {
+ if(!(*it)->profile.isEmpty())
+ t << " " << (*it)->target << "-" << "qmake_all";
+ }
+ }
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ if(project->isActiveConfig("no_empty_targets"))
+ t << "\n\t" << "@cd .";
+ t << endl << endl;
+ }
+
+ for(int s = 0; s < targetSuffixes.size(); ++s) {
+ QString suffix = targetSuffixes.at(s);
+ if(!(flags & SubTargetInstalls) && suffix.endsWith("install"))
+ continue;
+
+ t << suffix << ":";
+ for(int target = 0; target < targets.size(); ++target) {
+ SubTarget *subTarget = targets.at(target);
+ if((suffix == "make_first" || suffix == "make_default")
+ && project->values(subTarget->name + ".CONFIG").indexOf("no_default_target") != -1) {
+ continue;
+ }
+ QString targetRule = subTarget->target + "-" + suffix;
+ if(flags & SubTargetOrdered)
+ targetRule += "-ordered";
+ t << " " << targetRule;
+ }
+ if(suffix == "all" || suffix == "make_first")
+ t << varGlue("ALL_DEPS"," "," ","");
+ if(suffix == "clean")
+ t << varGlue("CLEAN_DEPS"," "," ","");
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << endl;
+ if(suffix == "clean") {
+ t << varGlue("QMAKE_CLEAN","\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ", "\n");
+ } else if(suffix == "distclean") {
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(!ofile.isEmpty())
+ t << "\t-$(DEL_FILE) " << ofile << endl;
+ t << varGlue("QMAKE_DISTCLEAN","\t-$(DEL_FILE) "," ","\n");
+ } else if(project->isActiveConfig("no_empty_targets")) {
+ t << "\t" << "@cd ." << endl;
+ }
+ }
+
+ // user defined targets
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::Iterator qut_it = qut.begin(); qut_it != qut.end(); ++qut_it) {
+ QString targ = var((*qut_it) + ".target"),
+ cmd = var((*qut_it) + ".commands"), deps;
+ if(targ.isEmpty())
+ targ = (*qut_it);
+ t << endl;
+
+ QStringList &deplist = project->values((*qut_it) + ".depends");
+ for(QStringList::Iterator dep_it = deplist.begin(); dep_it != deplist.end(); ++dep_it) {
+ QString dep = var((*dep_it) + ".target");
+ if(dep.isEmpty())
+ dep = Option::fixPathToTargetOS(*dep_it, false);
+ deps += " " + dep;
+ }
+ if(project->values((*qut_it) + ".CONFIG").indexOf("recursive") != -1) {
+ QSet<QString> recurse;
+ if(project->isSet((*qut_it) + ".recurse")) {
+ recurse = project->values((*qut_it) + ".recurse").toSet();
+ } else {
+ for(int target = 0; target < targets.size(); ++target)
+ recurse.insert(targets.at(target)->name);
+ }
+ for(int target = 0; target < targets.size(); ++target) {
+ SubTarget *subtarget = targets.at(target);
+ QString in_directory = subtarget->in_directory;
+ if(!in_directory.isEmpty() && !in_directory.endsWith(Option::dir_sep))
+ in_directory += Option::dir_sep;
+ QString out_directory = subtarget->out_directory;
+ if(!out_directory.isEmpty() && !out_directory.endsWith(Option::dir_sep))
+ out_directory += Option::dir_sep;
+ if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path))
+ out_directory = Option::output_dir + out_directory.mid(abs_source_path.length());
+
+ if(!recurse.contains(subtarget->name))
+ continue;
+ QString mkfile = subtarget->makefile;
+ if(!in_directory.isEmpty()) {
+ if(!out_directory.endsWith(Option::dir_sep))
+ mkfile.prepend(out_directory + Option::dir_sep);
+ else
+ mkfile.prepend(out_directory);
+ }
+ QString out_directory_cdin, out_directory_cdout;
+ MAKE_CD_IN_AND_OUT(out_directory);
+
+ //don't need the makefile arg if it isn't changed
+ QString makefilein;
+ if(subtarget->makefile != "$(MAKEFILE)")
+ makefilein = " -f " + subtarget->makefile;
+
+ //write the rule/depends
+ if(flags & SubTargetOrdered) {
+ const QString dep = subtarget->target + "-" + (*qut_it) + "_ordered";
+ t << dep << ": " << mkfile;
+ if(target)
+ t << " " << targets.at(target-1)->target << "-" << (*qut_it) << "_ordered ";
+ deps += " " + dep;
+ } else {
+ const QString dep = subtarget->target + "-" + (*qut_it);
+ t << dep << ": " << mkfile;
+ if(!subtarget->depends.isEmpty())
+ t << " " << valGlue(subtarget->depends, QString(), "-" + (*qut_it) + " ", "-" + (*qut_it));
+ deps += " " + dep;
+ }
+
+ QString sub_targ = targ;
+ if(project->isSet((*qut_it) + ".recurse_target"))
+ sub_targ = project->first((*qut_it) + ".recurse_target");
+
+ //write the commands
+ if(!out_directory.isEmpty()) {
+ t << out_directory_cdin
+ << "$(MAKE)" << makefilein << " " << sub_targ
+ << out_directory_cdout << endl;
+ } else {
+ t << "\n\t"
+ << "$(MAKE)" << makefilein << " " << sub_targ << endl;
+ }
+ }
+ }
+ if(project->isEmpty("QMAKE_NOFORCE") &&
+ project->values((*qut_it) + ".CONFIG").indexOf("phony") != -1)
+ deps += " FORCE";
+ t << targ << ":" << deps << "\n";
+ if(!cmd.isEmpty())
+ t << "\t" << cmd << endl;
+ }
+
+ if(flags & SubTargetInstalls) {
+ project->values("INSTALLDEPS") += "install_subtargets";
+ project->values("UNINSTALLDEPS") += "uninstall_subtargets";
+ writeInstalls(t, "INSTALLS", true);
+ }
+
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << "FORCE:" << endl << endl;
+}
+
+void
+MakefileGenerator::writeMakeQmake(QTextStream &t)
+{
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(project->isEmpty("QMAKE_FAILED_REQUIREMENTS") && !project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) {
+ QStringList files = fileFixify(Option::mkfile::project_files);
+ t << escapeDependencyPath(project->first("QMAKE_INTERNAL_PRL_FILE")) << ": " << "\n\t"
+ << "@$(QMAKE) -prl " << buildArgs() << " " << files.join(" ") << endl;
+ }
+
+ QString pfile = project->projectFile();
+ if(pfile != "(stdin)") {
+ QString qmake = build_args();
+ if(!ofile.isEmpty() && !project->isActiveConfig("no_autoqmake")) {
+ t << escapeFilePath(ofile) << ": " << escapeDependencyPath(fileFixify(pfile)) << " ";
+ if(Option::mkfile::do_cache)
+ t << escapeDependencyPath(fileFixify(Option::mkfile::cachefile)) << " ";
+ if(!specdir().isEmpty()) {
+ if(exists(Option::fixPathToLocalOS(specdir()+QDir::separator()+"qmake.conf")))
+ t << escapeDependencyPath(specdir() + Option::dir_sep + "qmake.conf") << " ";
+ }
+ const QStringList &included = project->values("QMAKE_INTERNAL_INCLUDED_FILES");
+ t << escapeDependencyPaths(included).join(" \\\n\t\t") << "\n\t"
+ << qmake << endl;
+ for(int include = 0; include < included.size(); ++include) {
+ const QString i(included.at(include));
+ if(!i.isEmpty())
+ t << i << ":" << endl;
+ }
+ }
+ if(project->first("QMAKE_ORIG_TARGET") != "qmake") {
+ t << "qmake: " <<
+ project->values("QMAKE_INTERNAL_QMAKE_DEPS").join(" \\\n\t\t");
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\t" << "@" << qmake << endl << endl;
+ }
+ }
+}
+
+QFileInfo
+MakefileGenerator::fileInfo(QString file) const
+{
+ static QHash<FileInfoCacheKey, QFileInfo> *cache = 0;
+ static QFileInfo noInfo = QFileInfo();
+ if(!cache) {
+ cache = new QHash<FileInfoCacheKey, QFileInfo>;
+ qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FileInfoCacheKey, QFileInfo> >, (void**)&cache);
+ }
+ FileInfoCacheKey cacheKey(file);
+ QFileInfo value = cache->value(cacheKey, noInfo);
+ if (value != noInfo)
+ return value;
+
+ QFileInfo fi(file);
+ if (fi.exists())
+ cache->insert(cacheKey, fi);
+ return fi;
+}
+
+QString
+MakefileGenerator::unescapeFilePath(const QString &path) const
+{
+ QString ret = path;
+ if(!ret.isEmpty()) {
+ if(ret.contains(QLatin1String("\\ ")))
+ ret.replace(QLatin1String("\\ "), QLatin1String(" "));
+ if(ret.contains(QLatin1Char('\"')))
+ ret.remove(QLatin1Char('\"'));
+ }
+ return ret;
+}
+
+QStringList
+MakefileGenerator::escapeFilePaths(const QStringList &paths) const
+{
+ QStringList ret;
+ for(int i = 0; i < paths.size(); ++i)
+ ret.append(escapeFilePath(paths.at(i)));
+ return ret;
+}
+
+QStringList
+MakefileGenerator::escapeDependencyPaths(const QStringList &paths) const
+{
+ QStringList ret;
+ for(int i = 0; i < paths.size(); ++i)
+ ret.append(escapeDependencyPath(paths.at(i)));
+ return ret;
+}
+
+QStringList
+MakefileGenerator::unescapeFilePaths(const QStringList &paths) const
+{
+ QStringList ret;
+ for(int i = 0; i < paths.size(); ++i)
+ ret.append(unescapeFilePath(paths.at(i)));
+ return ret;
+}
+
+QStringList
+MakefileGenerator::fileFixify(const QStringList& files, const QString &out_dir, const QString &in_dir,
+ FileFixifyType fix, bool canon) const
+{
+ if(files.isEmpty())
+ return files;
+ QStringList ret;
+ for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it) {
+ if(!(*it).isEmpty())
+ ret << fileFixify((*it), out_dir, in_dir, fix, canon);
+ }
+ return ret;
+}
+
+QString
+MakefileGenerator::fileFixify(const QString& file, const QString &out_d, const QString &in_d,
+ FileFixifyType fix, bool canon) const
+{
+ if(file.isEmpty())
+ return file;
+ QString ret = unescapeFilePath(file);
+
+ //do the fixin'
+ QString orig_file = ret;
+ if(ret.startsWith(QLatin1Char('~'))) {
+ if(ret.startsWith(QLatin1String("~/")))
+ ret = QDir::homePath() + ret.mid(1);
+ else
+ warn_msg(WarnLogic, "Unable to expand ~ in %s", ret.toLatin1().constData());
+ }
+ if(fix == FileFixifyAbsolute || (fix == FileFixifyDefault && project->isActiveConfig("no_fixpath"))) {
+ if(fix == FileFixifyAbsolute && QDir::isRelativePath(ret)) { //already absolute
+ QString pwd = qmake_getpwd();
+ if (!pwd.endsWith(QLatin1Char('/')))
+ pwd += QLatin1Char('/');
+ ret.prepend(pwd);
+ }
+ ret = Option::fixPathToTargetOS(ret, false, canon);
+ } else { //fix it..
+ QString out_dir = QDir(Option::output_dir).absoluteFilePath(out_d);
+ QString in_dir = QDir(qmake_getpwd()).absoluteFilePath(in_d);
+ {
+ QFileInfo in_fi(fileInfo(in_dir));
+ if(in_fi.exists())
+ in_dir = in_fi.canonicalFilePath();
+ QFileInfo out_fi(fileInfo(out_dir));
+ if(out_fi.exists())
+ out_dir = out_fi.canonicalFilePath();
+ }
+
+ QString qfile(Option::fixPathToLocalOS(ret, true, canon));
+ QFileInfo qfileinfo(fileInfo(qfile));
+ if(out_dir != in_dir || !qfileinfo.isRelative()) {
+ if(qfileinfo.isRelative()) {
+ ret = in_dir + "/" + qfile;
+ qfileinfo.setFile(ret);
+ }
+ ret = Option::fixPathToTargetOS(ret, false, canon);
+ if(canon && qfileinfo.exists() &&
+ file == Option::fixPathToTargetOS(ret, true, canon))
+ ret = Option::fixPathToTargetOS(qfileinfo.canonicalFilePath());
+ QString match_dir = Option::fixPathToTargetOS(out_dir, false, canon);
+ if(ret == match_dir) {
+ ret = "";
+ } else if(ret.startsWith(match_dir + Option::dir_sep)) {
+ ret = ret.mid(match_dir.length() + Option::dir_sep.length());
+ } else {
+ //figure out the depth
+ int depth = 4;
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+ Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
+ if(project && !project->isEmpty("QMAKE_PROJECT_DEPTH"))
+ depth = project->first("QMAKE_PROJECT_DEPTH").toInt();
+ else if(Option::mkfile::cachefile_depth != -1)
+ depth = Option::mkfile::cachefile_depth;
+ }
+ //calculate how much can be removed
+ QString dot_prefix;
+ for(int i = 1; i <= depth; i++) {
+ int sl = match_dir.lastIndexOf(Option::dir_sep);
+ if(sl == -1)
+ break;
+ match_dir = match_dir.left(sl);
+ if(match_dir.isEmpty())
+ break;
+ if(ret.startsWith(match_dir + Option::dir_sep)) {
+ //concat
+ int remlen = ret.length() - (match_dir.length() + 1);
+ if(remlen < 0)
+ remlen = 0;
+ ret = ret.right(remlen);
+ //prepend
+ for(int o = 0; o < i; o++)
+ dot_prefix += ".." + Option::dir_sep;
+ break;
+ }
+ }
+ ret.prepend(dot_prefix);
+ }
+ } else {
+ ret = Option::fixPathToTargetOS(ret, false, canon);
+ }
+ }
+ if(ret.isEmpty())
+ ret = ".";
+ debug_msg(3, "Fixed[%d,%d] %s :: to :: %s [%s::%s] [%s::%s]", fix, canon, orig_file.toLatin1().constData(),
+ ret.toLatin1().constData(), in_d.toLatin1().constData(), out_d.toLatin1().constData(),
+ qmake_getpwd().toLatin1().constData(), Option::output_dir.toLatin1().constData());
+ return ret;
+}
+
+void
+MakefileGenerator::checkMultipleDefinition(const QString &f, const QString &w)
+{
+ if(!(Option::warn_level & WarnLogic))
+ return;
+ QString file = f;
+ int slsh = f.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ file.remove(0, slsh + 1);
+ QStringList &l = project->values(w);
+ for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
+ QString file2((*val_it));
+ slsh = file2.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ file2.remove(0, slsh + 1);
+ if(file2 == file) {
+ warn_msg(WarnLogic, "Found potential symbol conflict of %s (%s) in %s",
+ file.toLatin1().constData(), (*val_it).toLatin1().constData(), w.toLatin1().constData());
+ break;
+ }
+ }
+}
+
+QMakeLocalFileName
+MakefileGenerator::fixPathForFile(const QMakeLocalFileName &file, bool forOpen)
+{
+ if(forOpen)
+ return QMakeLocalFileName(fileFixify(file.real(), qmake_getpwd(), Option::output_dir));
+ return QMakeLocalFileName(fileFixify(file.real()));
+}
+
+QFileInfo
+MakefileGenerator::findFileInfo(const QMakeLocalFileName &file)
+{
+ return fileInfo(file.local());
+}
+
+QMakeLocalFileName
+MakefileGenerator::findFileForDep(const QMakeLocalFileName &dep, const QMakeLocalFileName &file)
+{
+ QMakeLocalFileName ret;
+ if(!project->isEmpty("SKIP_DEPENDS")) {
+ bool found = false;
+ QStringList &nodeplist = project->values("SKIP_DEPENDS");
+ for(QStringList::Iterator it = nodeplist.begin();
+ it != nodeplist.end(); ++it) {
+ QRegExp regx((*it));
+ if(regx.indexIn(dep.local()) != -1) {
+ found = true;
+ break;
+ }
+ }
+ if(found)
+ return ret;
+ }
+
+ ret = QMakeSourceFileInfo::findFileForDep(dep, file);
+ if(!ret.isNull())
+ return ret;
+
+ //these are some "hacky" heuristics it will try to do on an include
+ //however these can be turned off at runtime, I'm not sure how
+ //reliable these will be, most likely when problems arise turn it off
+ //and see if they go away..
+ if(Option::mkfile::do_dep_heuristics) {
+ if(depHeuristicsCache.contains(dep.real()))
+ return depHeuristicsCache[dep.real()];
+
+ if(Option::output_dir != qmake_getpwd()
+ && QDir::isRelativePath(dep.real())) { //is it from the shadow tree
+ QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths();
+ depdirs.prepend(fileInfo(file.real()).absoluteDir().path());
+ QString pwd = qmake_getpwd();
+ if(pwd.at(pwd.length()-1) != '/')
+ pwd += '/';
+ for(int i = 0; i < depdirs.count(); i++) {
+ QString dir = depdirs.at(i).real();
+ if(!QDir::isRelativePath(dir) && dir.startsWith(pwd))
+ dir = dir.mid(pwd.length());
+ if(QDir::isRelativePath(dir)) {
+ if(!dir.endsWith(Option::dir_sep))
+ dir += Option::dir_sep;
+ QString shadow = fileFixify(dir + dep.local(), pwd, Option::output_dir);
+ if(exists(shadow)) {
+ ret = QMakeLocalFileName(shadow);
+ goto found_dep_from_heuristic;
+ }
+ }
+ }
+ }
+ { //is it from an EXTRA_TARGET
+ const QString dep_basename = dep.local().section(Option::dir_sep, -1);
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::Iterator it = qut.begin(); it != qut.end(); ++it) {
+ QString targ = var((*it) + ".target");
+ if(targ.isEmpty())
+ targ = (*it);
+ QString out = Option::fixPathToTargetOS(targ);
+ if(out == dep.real() || out.section(Option::dir_sep, -1) == dep_basename) {
+ ret = QMakeLocalFileName(out);
+ goto found_dep_from_heuristic;
+ }
+ }
+ }
+ { //is it from an EXTRA_COMPILER
+ const QString dep_basename = dep.local().section(Option::dir_sep, -1);
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = project->values((*it) + ".output").first();
+ if(tmp_out.isEmpty())
+ continue;
+ QStringList &tmp = project->values((*it) + ".input");
+ for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
+ QStringList &inputs = project->values((*it2));
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
+ QString out = Option::fixPathToTargetOS(unescapeFilePath(replaceExtraCompilerVariables(tmp_out, (*input), QString())));
+ if(out == dep.real() || out.section(Option::dir_sep, -1) == dep_basename) {
+ ret = QMakeLocalFileName(fileFixify(out, qmake_getpwd(), Option::output_dir));
+ goto found_dep_from_heuristic;
+ }
+ }
+ }
+ }
+ }
+ found_dep_from_heuristic:
+ depHeuristicsCache.insert(dep.real(), ret);
+ }
+ return ret;
+}
+
+QStringList
+&MakefileGenerator::findDependencies(const QString &file)
+{
+ const QString fixedFile = fileFixify(file);
+ if(!dependsCache.contains(fixedFile)) {
+#if 1
+ QStringList deps = QMakeSourceFileInfo::dependencies(file);
+ if(file != fixedFile)
+ deps += QMakeSourceFileInfo::dependencies(fixedFile);
+#else
+ QStringList deps = QMakeSourceFileInfo::dependencies(fixedFile);
+#endif
+ dependsCache.insert(fixedFile, deps);
+ }
+ return dependsCache[fixedFile];
+}
+
+QString
+MakefileGenerator::specdir(const QString &outdir)
+{
+#if 0
+ if(!spec.isEmpty())
+ return spec;
+#endif
+ spec = fileFixify(Option::mkfile::qmakespec, outdir);
+ return spec;
+}
+
+bool
+MakefileGenerator::openOutput(QFile &file, const QString &build) const
+{
+ {
+ QString outdir;
+ if(!file.fileName().isEmpty()) {
+ if(QDir::isRelativePath(file.fileName()))
+ file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run
+ QFileInfo fi(fileInfo(file.fileName()));
+ if(fi.isDir())
+ outdir = file.fileName() + '/';
+ }
+ if(!outdir.isEmpty() || file.fileName().isEmpty()) {
+ QString fname = "Makefile";
+ if(!project->isEmpty("MAKEFILE"))
+ fname = project->first("MAKEFILE");
+ file.setFileName(outdir + fname);
+ }
+ }
+ if(QDir::isRelativePath(file.fileName())) {
+ QString fname = Option::output_dir; //pwd when qmake was run
+ if(!fname.endsWith("/"))
+ fname += "/";
+ fname += file.fileName();
+ file.setFileName(fname);
+ }
+ if(!build.isEmpty())
+ file.setFileName(file.fileName() + "." + build);
+ if(project->isEmpty("QMAKE_MAKEFILE"))
+ project->values("QMAKE_MAKEFILE").append(file.fileName());
+ int slsh = file.fileName().lastIndexOf('/');
+ if(slsh != -1)
+ mkdir(file.fileName().left(slsh));
+ if(file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
+ QFileInfo fi(fileInfo(Option::output.fileName()));
+ QString od;
+ if(fi.isSymLink())
+ od = fileInfo(fi.readLink()).absolutePath();
+ else
+ od = fi.path();
+ od = QDir::fromNativeSeparators(od);
+ if(QDir::isRelativePath(od)) {
+ QString dir = Option::output_dir;
+ if (!dir.endsWith('/') && !od.isEmpty())
+ dir += '/';
+ od.prepend(dir);
+ }
+ Option::output_dir = od;
+ return true;
+ }
+ return false;
+}
+
+QString
+MakefileGenerator::pkgConfigFileName(bool fixify)
+{
+ QString ret = var("TARGET");
+ int slsh = ret.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ ret = ret.right(ret.length() - slsh - 1);
+ if(ret.startsWith("lib"))
+ ret = ret.mid(3);
+ int dot = ret.indexOf('.');
+ if(dot != -1)
+ ret = ret.left(dot);
+ ret += Option::pkgcfg_ext;
+ QString subdir = project->first("QMAKE_PKGCONFIG_DESTDIR");
+ if(!subdir.isEmpty()) {
+ // initOutPaths() appends dir_sep, but just to be safe..
+ if (!subdir.endsWith(Option::dir_sep))
+ ret.prepend(Option::dir_sep);
+ ret.prepend(subdir);
+ }
+ if(fixify) {
+ if(QDir::isRelativePath(ret) && !project->isEmpty("DESTDIR"))
+ ret.prepend(project->first("DESTDIR"));
+ ret = Option::fixPathToLocalOS(fileFixify(ret, qmake_getpwd(), Option::output_dir));
+ }
+ return ret;
+}
+
+QString
+MakefileGenerator::pkgConfigPrefix() const
+{
+ if(!project->isEmpty("QMAKE_PKGCONFIG_PREFIX"))
+ return project->first("QMAKE_PKGCONFIG_PREFIX");
+ return QLibraryInfo::location(QLibraryInfo::PrefixPath);
+}
+
+QString
+MakefileGenerator::pkgConfigFixPath(QString path) const
+{
+ QString prefix = pkgConfigPrefix();
+ if(path.startsWith(prefix))
+ path = path.replace(prefix, "${prefix}");
+ return path;
+}
+
+void
+MakefileGenerator::writePkgConfigFile()
+{
+ QString fname = pkgConfigFileName(), lname = fname;
+ mkdir(fileInfo(fname).path());
+ int slsh = lname.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ lname = lname.right(lname.length() - slsh - 1);
+ QFile ft(fname);
+ if(!ft.open(QIODevice::WriteOnly))
+ return;
+ project->values("ALL_DEPS").append(fileFixify(fname));
+ QTextStream t(&ft);
+
+ QString prefix = pkgConfigPrefix();
+ QString libDir = project->first("QMAKE_PKGCONFIG_LIBDIR");
+ if(libDir.isEmpty())
+ libDir = prefix + Option::dir_sep + "lib" + Option::dir_sep;
+ QString includeDir = project->first("QMAKE_PKGCONFIG_INCDIR");
+ if(includeDir.isEmpty())
+ includeDir = prefix + "/include";
+
+ t << "prefix=" << prefix << endl;
+ t << "exec_prefix=${prefix}\n"
+ << "libdir=" << pkgConfigFixPath(libDir) << "\n"
+ << "includedir=" << pkgConfigFixPath(includeDir) << endl;
+ // non-standard entry. Provides useful info normally only
+ // contained in the internal .qmake.cache file
+ t << varGlue("CONFIG", "qt_config=", " ", "") << endl;
+
+ //extra PKGCONFIG variables
+ const QStringList &pkgconfig_vars = project->values("QMAKE_PKGCONFIG_VARIABLES");
+ for(int i = 0; i < pkgconfig_vars.size(); ++i) {
+ QString var = project->first(pkgconfig_vars.at(i) + ".name"),
+ val = project->values(pkgconfig_vars.at(i) + ".value").join(" ");
+ if(var.isEmpty())
+ continue;
+ if(val.isEmpty()) {
+ const QStringList &var_vars = project->values(pkgconfig_vars.at(i) + ".variable");
+ for(int v = 0; v < var_vars.size(); ++v) {
+ const QStringList &vars = project->values(var_vars.at(v));
+ for(int var = 0; var < vars.size(); ++var) {
+ if(!val.isEmpty())
+ val += " ";
+ val += pkgConfigFixPath(vars.at(var));
+ }
+ }
+ }
+ t << var << "=" << val << endl;
+ }
+
+ t << endl;
+
+ QString name = project->first("QMAKE_PKGCONFIG_NAME");
+ if(name.isEmpty()) {
+ name = project->first("QMAKE_ORIG_TARGET").toLower();
+ name.replace(0, 1, name[0].toUpper());
+ }
+ t << "Name: " << name << endl;
+ QString desc = project->values("QMAKE_PKGCONFIG_DESCRIPTION").join(" ");
+ if(desc.isEmpty()) {
+ if(name.isEmpty()) {
+ desc = project->first("QMAKE_ORIG_TARGET").toLower();
+ desc.replace(0, 1, desc[0].toUpper());
+ } else {
+ desc = name;
+ }
+ if(project->first("TEMPLATE") == "lib") {
+ if(project->isActiveConfig("plugin"))
+ desc += " Plugin";
+ else
+ desc += " Library";
+ } else if(project->first("TEMPLATE") == "app") {
+ desc += " Application";
+ }
+ }
+ t << "Description: " << desc << endl;
+ t << "Version: " << project->first("VERSION") << endl;
+
+ // libs
+ t << "Libs: ";
+ QString pkgConfiglibDir;
+ QString pkgConfiglibName;
+ if (Option::target_mode == Option::TARG_MACX_MODE && project->isActiveConfig("lib_bundle")) {
+ pkgConfiglibDir = "-F${libdir}";
+ QString bundle;
+ if (!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME"))
+ bundle = unescapeFilePath(project->first("QMAKE_FRAMEWORK_BUNDLE_NAME"));
+ else
+ bundle = unescapeFilePath(project->first("TARGET"));
+ int suffix = bundle.lastIndexOf(".framework");
+ if (suffix != -1)
+ bundle = bundle.left(suffix);
+ pkgConfiglibName = "-framework " + bundle + " ";
+ } else {
+ pkgConfiglibDir = "-L${libdir}";
+ pkgConfiglibName = "-l" + lname.left(lname.length()-Option::libtool_ext.length());
+ }
+ t << pkgConfiglibDir << " " << pkgConfiglibName << " " << endl;
+
+ QStringList libs;
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) {
+ libs = project->values("QMAKE_INTERNAL_PRL_LIBS");
+ } else {
+ libs << "QMAKE_LIBS"; //obvious one
+ }
+ libs << "QMAKE_LIBS_PRIVATE";
+ libs << "QMAKE_LFLAGS_THREAD"; //not sure about this one, but what about things like -pthread?
+ t << "Libs.private: ";
+ for(QStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it) {
+ t << project->values((*it)).join(" ") << " ";
+ }
+ t << endl;
+
+ // flags
+ // ### too many
+ t << "Cflags: "
+ // << var("QMAKE_CXXFLAGS") << " "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << project->values("PRL_EXPORT_CXXFLAGS").join(" ")
+ << project->values("QMAKE_PKGCONFIG_CFLAGS").join(" ")
+ // << varGlue("DEFINES","-D"," -D"," ")
+ << " -I${includedir}" << endl;
+
+ // requires
+ const QString requires = project->values("QMAKE_PKGCONFIG_REQUIRES").join(" ");
+ if (!requires.isEmpty()) {
+ t << "Requires: " << requires << endl;
+ }
+
+ t << endl;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h
new file mode 100644
index 0000000000..e0ef52d251
--- /dev/null
+++ b/qmake/generators/makefile.h
@@ -0,0 +1,309 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAKEFILE_H
+#define MAKEFILE_H
+
+#include "option.h"
+#include "project.h"
+#include "makefiledeps.h"
+#include <qtextstream.h>
+#include <qlist.h>
+#include <qhash.h>
+#include <qfileinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN32
+#define QT_POPEN _popen
+#define QT_PCLOSE _pclose
+#else
+#define QT_POPEN popen
+#define QT_PCLOSE pclose
+#endif
+
+struct ReplaceExtraCompilerCacheKey
+{
+ mutable uint hash;
+ QString var, in, out, pwd;
+ ReplaceExtraCompilerCacheKey(const QString &v, const QStringList &i, const QStringList &o);
+ bool operator==(const ReplaceExtraCompilerCacheKey &f) const;
+ inline uint hashCode() const {
+ if(!hash)
+ hash = qHash(var) | qHash(in) | qHash(out) /*| qHash(pwd)*/;
+ return hash;
+ }
+};
+inline uint qHash(const ReplaceExtraCompilerCacheKey &f) { return f.hashCode(); }
+
+struct ReplaceExtraCompilerCacheKey;
+
+class MakefileGenerator : protected QMakeSourceFileInfo
+{
+ QString spec;
+ bool init_opath_already, init_already, no_io;
+ QHash<QString, bool> init_compiler_already;
+ QString build_args(const QString &outdir=QString());
+ void checkMultipleDefinition(const QString &, const QString &);
+
+ //internal caches
+ mutable QHash<QString, QMakeLocalFileName> depHeuristicsCache;
+ mutable QHash<QString, QStringList> dependsCache;
+ mutable QHash<ReplaceExtraCompilerCacheKey, QString> extraCompilerVariablesCache;
+
+protected:
+ QStringList createObjectList(const QStringList &sources);
+
+ //makefile style generator functions
+ void writeObj(QTextStream &, const QString &src);
+ void writeInstalls(QTextStream &t, const QString &installs, bool noBuild=false);
+ void writeHeader(QTextStream &t);
+ void writeSubDirs(QTextStream &t);
+ void writeMakeQmake(QTextStream &t);
+ void writeExtraVariables(QTextStream &t);
+ void writeExtraTargets(QTextStream &t);
+ void writeExtraCompilerTargets(QTextStream &t);
+ void writeExtraCompilerVariables(QTextStream &t);
+ virtual bool writeStubMakefile(QTextStream &t);
+ virtual bool writeMakefile(QTextStream &t);
+
+ QString pkgConfigPrefix() const;
+ QString pkgConfigFileName(bool fixify=true);
+ QString pkgConfigFixPath(QString) const;
+ void writePkgConfigFile(); // for pkg-config
+
+ //generating subtarget makefiles
+ struct SubTarget
+ {
+ QString name;
+ QString in_directory, out_directory;
+ QString profile, target, makefile;
+ QStringList depends;
+ };
+ enum SubTargetFlags {
+ SubTargetInstalls=0x01,
+ SubTargetOrdered=0x02,
+ SubTargetSkipDefaultVariables=0x04,
+ SubTargetSkipDefaultTargets=0x08,
+
+ SubTargetsNoFlags=0x00
+ };
+ QList<MakefileGenerator::SubTarget*> findSubDirsSubTargets() const;
+ void writeSubTargets(QTextStream &t, QList<SubTarget*> subtargets, int flags);
+
+ //extra compiler interface
+ bool verifyExtraCompiler(const QString &c, const QString &f);
+ virtual QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &);
+ inline QString replaceExtraCompilerVariables(const QString &val, const QString &in, const QString &out)
+ { return replaceExtraCompilerVariables(val, QStringList(in), QStringList(out)); }
+
+ //interface to the source file info
+ QMakeLocalFileName fixPathForFile(const QMakeLocalFileName &, bool);
+ QMakeLocalFileName findFileForDep(const QMakeLocalFileName &, const QMakeLocalFileName &);
+ QFileInfo findFileInfo(const QMakeLocalFileName &);
+ QMakeProject *project;
+
+ //escape
+ virtual QString unescapeFilePath(const QString &path) const;
+ virtual QStringList unescapeFilePaths(const QStringList &path) const;
+ virtual QString escapeFilePath(const QString &path) const { return path; }
+ virtual QString escapeDependencyPath(const QString &path) const { return escapeFilePath(path); }
+ QStringList escapeFilePaths(const QStringList &paths) const;
+ QStringList escapeDependencyPaths(const QStringList &paths) const;
+
+ //initialization
+ void verifyCompilers();
+ virtual void init();
+ void initOutPaths();
+ struct Compiler
+ {
+ QString variable_in;
+ enum CompilerFlag {
+ CompilerNoFlags = 0x00,
+ CompilerBuiltin = 0x01,
+ CompilerNoCheckDeps = 0x02,
+ CompilerRemoveNoExist = 0x04
+ };
+ uint flags, type;
+ };
+ void initCompiler(const Compiler &comp);
+ enum VPATHFlag {
+ VPATH_NoFlag = 0x00,
+ VPATH_WarnMissingFiles = 0x01,
+ VPATH_RemoveMissingFiles = 0x02,
+ VPATH_NoFixify = 0x04
+ };
+ QStringList findFilesInVPATH(QStringList l, uchar flags, const QString &var="");
+
+ inline int findExecutable(const QStringList &cmdline)
+ { int ret; canExecute(cmdline, &ret); return ret; }
+ bool canExecute(const QStringList &cmdline, int *argv0) const;
+ inline bool canExecute(const QString &cmdline) const
+ { return canExecute(cmdline.split(' '), 0); }
+
+ bool mkdir(const QString &dir) const;
+ QString mkdir_p_asstring(const QString &dir, bool escape=true) const;
+
+ //subclasses can use these to query information about how the generator was "run"
+ QString buildArgs(const QString &outdir=QString());
+ QString specdir(const QString &outdir=QString());
+
+ virtual QStringList &findDependencies(const QString &file);
+ virtual bool doDepends() const { return Option::mkfile::do_deps; }
+
+ void filterIncludedFiles(const QString &);
+ virtual void processSources() {
+ filterIncludedFiles("SOURCES");
+ filterIncludedFiles("GENERATED_SOURCES");
+ }
+
+ //for cross-platform dependent directories
+ virtual void usePlatformDir();
+
+ //for installs
+ virtual QString defaultInstall(const QString &);
+
+ //for prl
+ QString prlFileName(bool fixify=true);
+ void writePrlFile();
+ bool processPrlFile(QString &);
+ virtual void processPrlVariable(const QString &, const QStringList &);
+ virtual void processPrlFiles();
+ virtual void writePrlFile(QTextStream &);
+
+ //make sure libraries are found
+ virtual bool findLibraries();
+
+ //for retrieving values and lists of values
+ virtual QString var(const QString &var);
+ QString varGlue(const QString &var, const QString &before, const QString &glue, const QString &after);
+ QString varList(const QString &var);
+ QString val(const QStringList &varList);
+ QString valGlue(const QStringList &varList, const QString &before, const QString &glue, const QString &after);
+ QString valList(const QStringList &varList);
+
+ QString filePrefixRoot(const QString &, const QString &);
+
+ //file fixification to unify all file names into a single pattern
+ enum FileFixifyType { FileFixifyAbsolute, FileFixifyRelative, FileFixifyDefault };
+ QString fileFixify(const QString& file, const QString &out_dir=QString(),
+ const QString &in_dir=QString(), FileFixifyType fix=FileFixifyDefault, bool canon=true) const;
+ inline QString fileFixify(const QString& file, FileFixifyType fix, bool canon=true) const
+ { return fileFixify(file, QString(), QString(), fix, canon); }
+ QStringList fileFixify(const QStringList& files, const QString &out_dir=QString(),
+ const QString &in_dir=QString(), FileFixifyType fix=FileFixifyDefault, bool canon=true) const;
+ inline QStringList fileFixify(const QStringList& files, FileFixifyType fix, bool canon=true) const
+ { return fileFixify(files, QString(), QString(), fix, canon); }
+
+public:
+ MakefileGenerator();
+ virtual ~MakefileGenerator();
+ QMakeProject *projectFile() const;
+ void setProjectFile(QMakeProject *p);
+
+ void setNoIO(bool o);
+ bool noIO() const;
+
+ inline bool exists(QString file) const { return fileInfo(file).exists(); }
+ QFileInfo fileInfo(QString file) const;
+
+ static MakefileGenerator *create(QMakeProject *);
+ virtual bool write();
+ virtual bool writeProjectMakefile();
+ virtual bool supportsMetaBuild() { return true; }
+ virtual bool supportsMergedBuilds() { return false; }
+ virtual bool mergeBuildProject(MakefileGenerator * /*other*/) { return false; }
+ virtual bool openOutput(QFile &, const QString &build) const;
+ virtual bool isWindowsShell() const { return Option::host_mode == Option::HOST_WIN_MODE; }
+ virtual bool isForSymbianSbsv2() const { return false; } // FIXME: killme - i'm ugly!
+
+ /* The next one is to avoid having SymbianCommonGenerator as a virtually
+ inherited class of this class. Instead it is without a base class
+ (avoiding the virtual inheritance problem), and is allowed to use
+ functions defined in here.
+
+ To illustrate:
+ +-------------------+
+ | MakefileGenerator |
+ +-------------------+
+ ^ ^
+ | |
+ | X <-- Avoid this inheritance
+ | |
+ +------------------------+ +------------------------+
+ | UnixMakefileGenerator | | SymbianCommonGenerator |
+ | or | | |
+ | NmakeMakefileGenerator | | |
+ +------------------------+ +------------------------+
+ ^ ^
+ | |
+ | |
+ | |
+ +-----------------------------+
+ | SymbianMakefileTemplate<> |
+ +-----------------------------+
+
+ We want to avoid the famous diamond problem, because if we have that, we need
+ virtual inheritance, which not all compilers like. Therefore, we break the
+ link as illustrated. Instead, we have a pointer to MakefileGenerator inside
+ SymbianCommonGenerator, and allows full access by making it a friend here.
+ */
+ friend class SymbianCommonGenerator;
+};
+
+inline void MakefileGenerator::setNoIO(bool o)
+{ no_io = o; }
+
+inline bool MakefileGenerator::noIO() const
+{ return no_io; }
+
+inline QString MakefileGenerator::defaultInstall(const QString &)
+{ return QString(""); }
+
+inline bool MakefileGenerator::findLibraries()
+{ return true; }
+
+inline MakefileGenerator::~MakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // MAKEFILE_H
diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp
new file mode 100644
index 0000000000..56dc9917c0
--- /dev/null
+++ b/qmake/generators/makefiledeps.cpp
@@ -0,0 +1,961 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "makefiledeps.h"
+#include "option.h"
+#include <qdir.h>
+#include <qdatetime.h>
+#include <qfileinfo.h>
+#include <qbuffer.h>
+#include <qplatformdefs.h>
+#if defined(Q_OS_UNIX)
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
+#include <qdebug.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#include <share.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if 1
+#define qmake_endOfLine(c) (c == '\r' || c == '\n')
+#else
+inline bool qmake_endOfLine(const char &c) { return (c == '\r' || c == '\n'); }
+#endif
+
+//#define QMAKE_USE_CACHE
+
+QMakeLocalFileName::QMakeLocalFileName(const QString &name) : is_null(name.isNull())
+{
+ if(!name.isEmpty()) {
+ if(name.at(0) == QLatin1Char('"') && name.at(name.length()-2) == QLatin1Char('"'))
+ real_name = name.mid(1, name.length()-2);
+ else
+ real_name = name;
+ }
+}
+const QString
+&QMakeLocalFileName::local() const
+{
+ if(!is_null && local_name.isNull())
+ local_name = Option::fixPathToLocalOS(real_name, true);
+ return local_name;
+}
+
+struct SourceDependChildren;
+struct SourceFile {
+ SourceFile() : deps(0), type(QMakeSourceFileInfo::TYPE_UNKNOWN),
+ mocable(0), traversed(0), exists(1),
+ moc_checked(0), dep_checked(0), included_count(0) { }
+ ~SourceFile();
+ QMakeLocalFileName file;
+ SourceDependChildren *deps;
+ QMakeSourceFileInfo::SourceFileType type;
+ uint mocable : 1, traversed : 1, exists : 1;
+ uint moc_checked : 1, dep_checked : 1;
+ uchar included_count;
+};
+struct SourceDependChildren {
+ SourceFile **children;
+ int num_nodes, used_nodes;
+ SourceDependChildren() : children(0), num_nodes(0), used_nodes(0) { }
+ ~SourceDependChildren() { if(children) free(children); children = 0; }
+ void addChild(SourceFile *s) {
+ if(num_nodes <= used_nodes) {
+ num_nodes += 200;
+ children = (SourceFile**)realloc(children, sizeof(SourceFile*)*(num_nodes));
+ }
+ children[used_nodes++] = s;
+ }
+};
+SourceFile::~SourceFile() { delete deps; }
+class SourceFiles {
+ int hash(const char *);
+public:
+ SourceFiles();
+ ~SourceFiles();
+
+ SourceFile *lookupFile(const char *);
+ inline SourceFile *lookupFile(const QString &f) { return lookupFile(f.toLatin1().constData()); }
+ inline SourceFile *lookupFile(const QMakeLocalFileName &f) { return lookupFile(f.local().toLatin1().constData()); }
+ void addFile(SourceFile *, const char *k=0, bool own=true);
+
+ struct SourceFileNode {
+ SourceFileNode() : key(0), next(0), file(0), own_file(1) { }
+ ~SourceFileNode() {
+ delete [] key;
+ if(own_file)
+ delete file;
+ }
+ char *key;
+ SourceFileNode *next;
+ SourceFile *file;
+ uint own_file : 1;
+ } **nodes;
+ int num_nodes;
+};
+SourceFiles::SourceFiles()
+{
+ nodes = (SourceFileNode**)malloc(sizeof(SourceFileNode*)*(num_nodes=3037));
+ for(int n = 0; n < num_nodes; n++)
+ nodes[n] = 0;
+}
+
+SourceFiles::~SourceFiles()
+{
+ for(int n = 0; n < num_nodes; n++) {
+ for(SourceFileNode *next = nodes[n]; next;) {
+ SourceFileNode *next_next = next->next;
+ delete next;
+ next = next_next;
+ }
+ }
+ free(nodes);
+}
+
+int SourceFiles::hash(const char *file)
+{
+ uint h = 0, g;
+ while (*file) {
+ h = (h << 4) + *file;
+ if ((g = (h & 0xf0000000)) != 0)
+ h ^= g >> 23;
+ h &= ~g;
+ file++;
+ }
+ return h;
+}
+
+SourceFile *SourceFiles::lookupFile(const char *file)
+{
+ int h = hash(file) % num_nodes;
+ for(SourceFileNode *p = nodes[h]; p; p = p->next) {
+ if(!strcmp(p->key, file))
+ return p->file;
+ }
+ return 0;
+}
+
+void SourceFiles::addFile(SourceFile *p, const char *k, bool own_file)
+{
+ QByteArray ba = p->file.local().toLatin1();
+ if(!k)
+ k = ba;
+ int h = hash(k) % num_nodes;
+ SourceFileNode *pn = new SourceFileNode;
+ pn->own_file = own_file;
+ pn->key = qstrdup(k);
+ pn->file = p;
+ pn->next = nodes[h];
+ nodes[h] = pn;
+}
+
+void QMakeSourceFileInfo::dependTreeWalker(SourceFile *node, SourceDependChildren *place)
+{
+ if(node->traversed || !node->exists)
+ return;
+ place->addChild(node);
+ node->traversed = true; //set flag
+ if(node->deps) {
+ for(int i = 0; i < node->deps->used_nodes; i++)
+ dependTreeWalker(node->deps->children[i], place);
+ }
+}
+
+void QMakeSourceFileInfo::setDependencyPaths(const QList<QMakeLocalFileName> &l)
+{
+ // Ensure that depdirs does not contain the same paths several times, to minimize the stats
+ QList<QMakeLocalFileName> ll;
+ for (int i = 0; i < l.count(); ++i) {
+ if (!ll.contains(l.at(i)))
+ ll.append(l.at(i));
+ }
+ depdirs = ll;
+}
+
+QStringList QMakeSourceFileInfo::dependencies(const QString &file)
+{
+ QStringList ret;
+ if(!files)
+ return ret;
+
+ if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file))) {
+ if(node->deps) {
+ /* I stick them into a SourceDependChildren here because it is faster to just
+ iterate over the list to stick them in the list, and reset the flag, then it is
+ to loop over the tree (about 50% faster I saw) --Sam */
+ SourceDependChildren place;
+ for(int i = 0; i < node->deps->used_nodes; i++)
+ dependTreeWalker(node->deps->children[i], &place);
+ if(place.children) {
+ for(int i = 0; i < place.used_nodes; i++) {
+ place.children[i]->traversed = false; //reset flag
+ ret.append(place.children[i]->file.real());
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+int
+QMakeSourceFileInfo::included(const QString &file)
+{
+ if (!files)
+ return 0;
+
+ if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file)))
+ return node->included_count;
+ return 0;
+}
+
+bool QMakeSourceFileInfo::mocable(const QString &file)
+{
+ if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file)))
+ return node->mocable;
+ return false;
+}
+
+QMakeSourceFileInfo::QMakeSourceFileInfo(const QString &cf)
+{
+ //dep_mode
+ dep_mode = Recursive;
+
+ //quick project lookups
+ includes = files = 0;
+ files_changed = false;
+
+ //buffer
+ spare_buffer = 0;
+ spare_buffer_size = 0;
+
+ //cache
+ cachefile = cf;
+ if(!cachefile.isEmpty())
+ loadCache(cachefile);
+}
+
+QMakeSourceFileInfo::~QMakeSourceFileInfo()
+{
+ //cache
+ if(!cachefile.isEmpty() /*&& files_changed*/)
+ saveCache(cachefile);
+
+ //buffer
+ if(spare_buffer) {
+ free(spare_buffer);
+ spare_buffer = 0;
+ spare_buffer_size = 0;
+ }
+
+ //quick project lookup
+ delete files;
+ delete includes;
+}
+
+void QMakeSourceFileInfo::setCacheFile(const QString &cf)
+{
+ cachefile = cf;
+ loadCache(cachefile);
+}
+
+void QMakeSourceFileInfo::addSourceFiles(const QStringList &l, uchar seek,
+ QMakeSourceFileInfo::SourceFileType type)
+{
+ for(int i=0; i<l.size(); ++i)
+ addSourceFile(l.at(i), seek, type);
+}
+void QMakeSourceFileInfo::addSourceFile(const QString &f, uchar seek,
+ QMakeSourceFileInfo::SourceFileType type)
+{
+ if(!files)
+ files = new SourceFiles;
+
+ QMakeLocalFileName fn(f);
+ SourceFile *file = files->lookupFile(fn);
+ if(!file) {
+ file = new SourceFile;
+ file->file = fn;
+ files->addFile(file);
+ } else {
+ if(file->type != type && file->type != TYPE_UNKNOWN && type != TYPE_UNKNOWN)
+ warn_msg(WarnLogic, "%s is marked as %d, then %d!", f.toLatin1().constData(),
+ file->type, type);
+ }
+ if(type != TYPE_UNKNOWN)
+ file->type = type;
+
+ if(seek & SEEK_MOCS && !file->moc_checked)
+ findMocs(file);
+ if(seek & SEEK_DEPS && !file->dep_checked)
+ findDeps(file);
+}
+
+bool QMakeSourceFileInfo::containsSourceFile(const QString &f, SourceFileType type)
+{
+ if(SourceFile *file = files->lookupFile(QMakeLocalFileName(f)))
+ return (file->type == type || file->type == TYPE_UNKNOWN || type == TYPE_UNKNOWN);
+ return false;
+}
+
+char *QMakeSourceFileInfo::getBuffer(int s) {
+ if(!spare_buffer || spare_buffer_size < s)
+ spare_buffer = (char *)realloc(spare_buffer, spare_buffer_size=s);
+ return spare_buffer;
+}
+
+#ifndef S_ISDIR
+#define S_ISDIR(x) (x & _S_IFDIR)
+#endif
+
+QMakeLocalFileName QMakeSourceFileInfo::fixPathForFile(const QMakeLocalFileName &f, bool)
+{
+ return f;
+}
+
+QMakeLocalFileName QMakeSourceFileInfo::findFileForDep(const QMakeLocalFileName &/*dep*/,
+ const QMakeLocalFileName &/*file*/)
+{
+ return QMakeLocalFileName();
+}
+
+QFileInfo QMakeSourceFileInfo::findFileInfo(const QMakeLocalFileName &dep)
+{
+ return QFileInfo(dep.real());
+}
+
+bool QMakeSourceFileInfo::findDeps(SourceFile *file)
+{
+ if(file->dep_checked || file->type == TYPE_UNKNOWN)
+ return true;
+ files_changed = true;
+ file->dep_checked = true;
+
+ const QMakeLocalFileName sourceFile = fixPathForFile(file->file, true);
+
+ struct stat fst;
+ char *buffer = 0;
+ int buffer_len = 0;
+ {
+ int fd;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ if (_sopen_s(&fd, sourceFile.local().toLatin1().constData(),
+ _O_RDONLY, _SH_DENYNO, _S_IREAD) != 0)
+ fd = -1;
+#else
+ fd = open(sourceFile.local().toLatin1().constData(), O_RDONLY);
+#endif
+ if(fd == -1 || fstat(fd, &fst) || S_ISDIR(fst.st_mode))
+ return false;
+ buffer = getBuffer(fst.st_size);
+ for(int have_read = 0;
+ (have_read = QT_READ(fd, buffer + buffer_len, fst.st_size - buffer_len));
+ buffer_len += have_read) ;
+ QT_CLOSE(fd);
+ }
+ if(!buffer)
+ return false;
+ if(!file->deps)
+ file->deps = new SourceDependChildren;
+
+ int line_count = 1;
+
+ for(int x = 0; x < buffer_len; ++x) {
+ bool try_local = true;
+ char *inc = 0;
+ if(file->type == QMakeSourceFileInfo::TYPE_UI) {
+ // skip whitespaces
+ while(x < buffer_len && (*(buffer+x) == ' ' || *(buffer+x) == '\t'))
+ ++x;
+ if(*(buffer + x) == '<') {
+ ++x;
+ if(buffer_len >= x + 12 && !strncmp(buffer + x, "includehint", 11) &&
+ (*(buffer + x + 11) == ' ' || *(buffer + x + 11) == '>')) {
+ for(x += 11; *(buffer + x) != '>'; ++x) ;
+ int inc_len = 0;
+ for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len) ;
+ *(buffer + x + inc_len) = '\0';
+ inc = buffer + x;
+ } else if(buffer_len >= x + 13 && !strncmp(buffer + x, "customwidget", 12) &&
+ (*(buffer + x + 12) == ' ' || *(buffer + x + 12) == '>')) {
+ for(x += 13; *(buffer + x) != '>'; ++x) ; //skip up to >
+ while(x < buffer_len) {
+ for(x++; *(buffer + x) != '<'; ++x) ; //skip up to <
+ x++;
+ if(buffer_len >= x + 7 && !strncmp(buffer+x, "header", 6) &&
+ (*(buffer + x + 6) == ' ' || *(buffer + x + 6) == '>')) {
+ for(x += 7; *(buffer + x) != '>'; ++x) ; //skip up to >
+ int inc_len = 0;
+ for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len) ;
+ *(buffer + x + inc_len) = '\0';
+ inc = buffer + x;
+ break;
+ } else if(buffer_len >= x + 14 && !strncmp(buffer+x, "/customwidget", 13) &&
+ (*(buffer + x + 13) == ' ' || *(buffer + x + 13) == '>')) {
+ x += 14;
+ break;
+ }
+ }
+ } else if(buffer_len >= x + 8 && !strncmp(buffer + x, "include", 7) &&
+ (*(buffer + x + 7) == ' ' || *(buffer + x + 7) == '>')) {
+ for(x += 8; *(buffer + x) != '>'; ++x) {
+ if(buffer_len >= x + 9 && *(buffer + x) == 'i' &&
+ !strncmp(buffer + x, "impldecl", 8)) {
+ for(x += 8; *(buffer + x) != '='; ++x) ;
+ if(*(buffer + x) != '=')
+ continue;
+ for(++x; *(buffer+x) == '\t' || *(buffer+x) == ' '; ++x) ;
+ char quote = 0;
+ if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
+ quote = *(buffer + x);
+ ++x;
+ }
+ int val_len;
+ for(val_len = 0; true; ++val_len) {
+ if(quote) {
+ if(*(buffer+x+val_len) == quote)
+ break;
+ } else if(*(buffer + x + val_len) == '>' ||
+ *(buffer + x + val_len) == ' ') {
+ break;
+ }
+ }
+//? char saved = *(buffer + x + val_len);
+ *(buffer + x + val_len) = '\0';
+ if(!strcmp(buffer+x, "in implementation")) {
+ //### do this
+ }
+ }
+ }
+ int inc_len = 0;
+ for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len) ;
+ *(buffer + x + inc_len) = '\0';
+ inc = buffer + x;
+ }
+ }
+ //read past new line now..
+ for(; x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ;
+ ++line_count;
+ } else if(file->type == QMakeSourceFileInfo::TYPE_QRC) {
+ } else if(file->type == QMakeSourceFileInfo::TYPE_C) {
+ for(int beginning=1; x < buffer_len; ++x) {
+ // whitespace comments and line-endings
+ for(; x < buffer_len; ++x) {
+ if(*(buffer+x) == ' ' || *(buffer+x) == '\t') {
+ // keep going
+ } else if(*(buffer+x) == '/') {
+ ++x;
+ if(buffer_len >= x) {
+ if(*(buffer+x) == '/') { //c++ style comment
+ for(; x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ;
+ beginning = 1;
+ } else if(*(buffer+x) == '*') { //c style comment
+ for(++x; x < buffer_len; ++x) {
+ if(*(buffer+x) == '*') {
+ if(x < buffer_len-1 && *(buffer + (x+1)) == '/') {
+ ++x;
+ break;
+ }
+ } else if(qmake_endOfLine(*(buffer+x))) {
+ ++line_count;
+ }
+ }
+ }
+ }
+ } else if(qmake_endOfLine(*(buffer+x))) {
+ ++line_count;
+ beginning = 1;
+ } else {
+ break;
+ }
+ }
+
+ if(x >= buffer_len)
+ break;
+
+ // preprocessor directive
+ if(beginning && *(buffer+x) == '#')
+ break;
+
+ // quoted strings
+ if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
+ const char term = *(buffer+(x++));
+ for(; x < buffer_len; ++x) {
+ if(*(buffer+x) == term) {
+ ++x;
+ break;
+ } else if(*(buffer+x) == '\\') {
+ ++x;
+ } else if(qmake_endOfLine(*(buffer+x))) {
+ ++line_count;
+ }
+ }
+ }
+ beginning = 0;
+ }
+ if(x >= buffer_len)
+ break;
+
+ //got a preprocessor symbol
+ ++x;
+ while(x < buffer_len) {
+ if(*(buffer+x) != ' ' && *(buffer+x) != '\t')
+ break;
+ ++x;
+ }
+
+ int keyword_len = 0;
+ const char *keyword = buffer+x;
+ while(x+keyword_len < buffer_len) {
+ if(((*(buffer+x+keyword_len) < 'a' || *(buffer+x+keyword_len) > 'z')) &&
+ *(buffer+x+keyword_len) != '_') {
+ for(x+=keyword_len; //skip spaces after keyword
+ x < buffer_len && (*(buffer+x) == ' ' || *(buffer+x) == '\t');
+ x++) ;
+ break;
+ } else if(qmake_endOfLine(*(buffer+x+keyword_len))) {
+ x += keyword_len-1;
+ keyword_len = 0;
+ break;
+ }
+ keyword_len++;
+ }
+
+ if(keyword_len == 7 && !strncmp(keyword, "include", keyword_len)) {
+ char term = *(buffer + x);
+ if(term == '<') {
+ try_local = false;
+ term = '>';
+ } else if(term != '"') { //wtf?
+ continue;
+ }
+ x++;
+
+ int inc_len;
+ for(inc_len = 0; *(buffer + x + inc_len) != term && !qmake_endOfLine(*(buffer + x + inc_len)); ++inc_len) ;
+ *(buffer + x + inc_len) = '\0';
+ inc = buffer + x;
+ x += inc_len;
+ } else if(keyword_len == 13 && !strncmp(keyword, "qmake_warning", keyword_len)) {
+ char term = 0;
+ if(*(buffer + x) == '"')
+ term = '"';
+ if(*(buffer + x) == '\'')
+ term = '\'';
+ if(term)
+ x++;
+
+ int msg_len;
+ for(msg_len = 0; (term && *(buffer + x + msg_len) != term) &&
+ !qmake_endOfLine(*(buffer + x + msg_len)); ++msg_len) ;
+ *(buffer + x + msg_len) = '\0';
+ debug_msg(0, "%s:%d %s -- %s", file->file.local().toLatin1().constData(), line_count, keyword, buffer+x);
+ x += msg_len;
+ } else if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
+ const char term = *(buffer+(x++));
+ while(x < buffer_len) {
+ if(*(buffer+x) == term)
+ break;
+ if(*(buffer+x) == '\\') {
+ x+=2;
+ } else {
+ if(qmake_endOfLine(*(buffer+x)))
+ ++line_count;
+ ++x;
+ }
+ }
+ } else {
+ --x;
+ }
+ }
+
+ if(inc) {
+ if(!includes)
+ includes = new SourceFiles;
+ SourceFile *dep = includes->lookupFile(inc);
+ if(!dep) {
+ bool exists = false;
+ QMakeLocalFileName lfn(inc);
+ if(QDir::isRelativePath(lfn.real())) {
+ if(try_local) {
+ QDir sourceDir = findFileInfo(sourceFile).dir();
+ QMakeLocalFileName f(sourceDir.absoluteFilePath(lfn.local()));
+ if(findFileInfo(f).exists()) {
+ lfn = fixPathForFile(f);
+ exists = true;
+ }
+ }
+ if(!exists) { //path lookup
+ for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin(); it != depdirs.end(); ++it) {
+ QMakeLocalFileName f((*it).real() + Option::dir_sep + lfn.real());
+ QFileInfo fi(findFileInfo(f));
+ if(fi.exists() && !fi.isDir()) {
+ lfn = fixPathForFile(f);
+ exists = true;
+ break;
+ }
+ }
+ }
+ if(!exists) { //heuristic lookup
+ lfn = findFileForDep(QMakeLocalFileName(inc), file->file);
+ if((exists = !lfn.isNull()))
+ lfn = fixPathForFile(lfn);
+ }
+ } else {
+ exists = QFile::exists(lfn.real());
+ }
+ if(!lfn.isNull()) {
+ dep = files->lookupFile(lfn);
+ if(!dep) {
+ dep = new SourceFile;
+ dep->file = lfn;
+ dep->type = QMakeSourceFileInfo::TYPE_C;
+ files->addFile(dep);
+ includes->addFile(dep, inc, false);
+ }
+ dep->exists = exists;
+ }
+ }
+ if(dep && dep->file != file->file) {
+ dep->included_count++;
+ if(dep->exists) {
+ debug_msg(5, "%s:%d Found dependency to %s", file->file.real().toLatin1().constData(),
+ line_count, dep->file.local().toLatin1().constData());
+ file->deps->addChild(dep);
+ }
+ }
+ }
+ }
+ if(dependencyMode() == Recursive) { //done last because buffer is shared
+ for(int i = 0; i < file->deps->used_nodes; i++) {
+ if(!file->deps->children[i]->deps)
+ findDeps(file->deps->children[i]);
+ }
+ }
+ return true;
+}
+
+bool QMakeSourceFileInfo::findMocs(SourceFile *file)
+{
+ if(file->moc_checked)
+ return true;
+ files_changed = true;
+ file->moc_checked = true;
+
+ int buffer_len;
+ char *buffer = 0;
+ {
+ struct stat fst;
+ int fd;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ if (_sopen_s(&fd, fixPathForFile(file->file, true).local().toLocal8Bit().constData(),
+ _O_RDONLY, _SH_DENYRW, _S_IREAD) != 0)
+ fd = -1;
+#else
+ fd = open(fixPathForFile(file->file, true).local().toLocal8Bit().constData(), O_RDONLY);
+#endif
+ if(fd == -1 || fstat(fd, &fst) || S_ISDIR(fst.st_mode))
+ return false; //shouldn't happen
+ buffer = getBuffer(fst.st_size);
+ for(int have_read = buffer_len = 0;
+ (have_read = QT_READ(fd, buffer + buffer_len, fst.st_size - buffer_len));
+ buffer_len += have_read) ;
+ QT_CLOSE(fd);
+ }
+
+ debug_msg(2, "findMocs: %s", file->file.local().toLatin1().constData());
+ int line_count = 1;
+ bool ignore_qobject = false, ignore_qgadget = false;
+ /* qmake ignore Q_GADGET */
+ /* qmake ignore Q_OBJECT */
+ for(int x = 0; x < buffer_len; x++) {
+ if(*(buffer + x) == '/') {
+ ++x;
+ if(buffer_len >= x) {
+ if(*(buffer + x) == '/') { //c++ style comment
+ for(;x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x) ;
+ } else if(*(buffer + x) == '*') { //c style comment
+ for(++x; x < buffer_len; ++x) {
+ if(*(buffer + x) == 't' || *(buffer + x) == 'q') { //ignore
+ if(buffer_len >= (x + 20) &&
+ !strncmp(buffer + x + 1, "make ignore Q_OBJECT", 20)) {
+ debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_OBJECT\"",
+ file->file.real().toLatin1().constData(), line_count);
+ x += 20;
+ ignore_qobject = true;
+ } else if(buffer_len >= (x + 20) &&
+ !strncmp(buffer + x + 1, "make ignore Q_GADGET", 20)) {
+ debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_GADGET\"",
+ file->file.real().toLatin1().constData(), line_count);
+ x += 20;
+ ignore_qgadget = true;
+ }
+ } else if(*(buffer + x) == '*') {
+ if(buffer_len >= (x+1) && *(buffer + (x+1)) == '/') {
+ ++x;
+ break;
+ }
+ } else if(Option::debug_level && qmake_endOfLine(*(buffer + x))) {
+ ++line_count;
+ }
+ }
+ }
+ }
+ } else if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
+ const char term = *(buffer+(x++));
+ while(x < buffer_len) {
+ if(*(buffer+x) == term)
+ break;
+ if(*(buffer+x) == '\\') {
+ x+=2;
+ } else {
+ if(qmake_endOfLine(*(buffer+x)))
+ ++line_count;
+ ++x;
+ }
+ }
+ }
+ if(Option::debug_level && qmake_endOfLine(*(buffer+x)))
+ ++line_count;
+ if(((buffer_len > x+2 && *(buffer+x+1) == 'Q' && *(buffer+x+2) == '_')
+ ||
+ (buffer_len > x+4 && *(buffer+x+1) == 'Q' && *(buffer+x+2) == 'O'
+ && *(buffer+x+3) == 'M' && *(buffer+x+4) == '_'))
+ &&
+ *(buffer + x) != '_' &&
+ (*(buffer + x) < 'a' || *(buffer + x) > 'z') &&
+ (*(buffer + x) < 'A' || *(buffer + x) > 'Z') &&
+ (*(buffer + x) < '0' || *(buffer + x) > '9')) {
+ ++x;
+ int match = 0;
+ static const char *interesting[] = { "OBJECT", "GADGET",
+ "M_OBJECT" };
+ for(int interest = 0, m1, m2; interest < 3; ++interest) {
+ if(interest == 0 && ignore_qobject)
+ continue;
+ else if(interest == 1 && ignore_qgadget)
+ continue;
+ for(m1 = 0, m2 = 0; *(interesting[interest]+m1); ++m1) {
+ if(*(interesting[interest]+m1) != *(buffer+x+2+m1)) {
+ m2 = -1;
+ break;
+ }
+ ++m2;
+ }
+ if(m1 == m2) {
+ match = m2 + 2;
+ break;
+ }
+ }
+ if(match && *(buffer+x+match) != '_' &&
+ (*(buffer+x+match) < 'a' || *(buffer+x+match) > 'z') &&
+ (*(buffer+x+match) < 'A' || *(buffer+x+match) > 'Z') &&
+ (*(buffer+x+match) < '0' || *(buffer+x+match) > '9')) {
+ if(Option::debug_level) {
+ *(buffer+x+match) = '\0';
+ debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s", file->file.real().toLatin1().constData(),
+ line_count, buffer+x);
+ }
+ file->mocable = true;
+ return true;
+ }
+ }
+ }
+ return true;
+}
+
+
+void QMakeSourceFileInfo::saveCache(const QString &cf)
+{
+#ifdef QMAKE_USE_CACHE
+ if(cf.isEmpty())
+ return;
+
+ QFile file(QMakeLocalFileName(cf).local());
+ if(file.open(QIODevice::WriteOnly)) {
+ QTextStream stream(&file);
+ stream << qmake_version() << endl << endl; //version
+ { //cache verification
+ QMap<QString, QStringList> verify = getCacheVerification();
+ stream << verify.count() << endl;
+ for(QMap<QString, QStringList>::iterator it = verify.begin();
+ it != verify.end(); ++it) {
+ stream << it.key() << endl << it.value().join(";") << endl;
+ }
+ stream << endl;
+ }
+ if(files->nodes) {
+ for(int file = 0; file < files->num_nodes; ++file) {
+ for(SourceFiles::SourceFileNode *node = files->nodes[file]; node; node = node->next) {
+ stream << node->file->file.local() << endl; //source
+ stream << node->file->type << endl; //type
+
+ //depends
+ stream << ";";
+ if(node->file->deps) {
+ for(int depend = 0; depend < node->file->deps->used_nodes; ++depend) {
+ if(depend)
+ stream << ";";
+ stream << node->file->deps->children[depend]->file.local();
+ }
+ }
+ stream << endl;
+
+ stream << node->file->mocable << endl; //mocable
+ stream << endl; //just for human readability
+ }
+ }
+ }
+ stream.flush();
+ file.close();
+ }
+#else
+ Q_UNUSED(cf);
+#endif
+}
+
+void QMakeSourceFileInfo::loadCache(const QString &cf)
+{
+ if(cf.isEmpty())
+ return;
+
+#ifdef QMAKE_USE_CACHE
+ QMakeLocalFileName cache_file(cf);
+ int fd = open(QMakeLocalFileName(cf).local().toLatin1(), O_RDONLY);
+ if(fd == -1)
+ return;
+ QFileInfo cache_fi = findFileInfo(cache_file);
+ if(!cache_fi.exists() || cache_fi.isDir())
+ return;
+
+ QFile file;
+ if(!file.open(QIODevice::ReadOnly, fd))
+ return;
+ QTextStream stream(&file);
+
+ if(stream.readLine() == qmake_version()) { //version check
+ stream.skipWhiteSpace();
+
+ bool verified = true;
+ { //cache verification
+ QMap<QString, QStringList> verify;
+ int len = stream.readLine().toInt();
+ for(int i = 0; i < len; ++i) {
+ QString var = stream.readLine();
+ QString val = stream.readLine();
+ verify.insert(var, val.split(';', QString::SkipEmptyParts));
+ }
+ verified = verifyCache(verify);
+ }
+ if(verified) {
+ stream.skipWhiteSpace();
+ if(!files)
+ files = new SourceFiles;
+ while(!stream.atEnd()) {
+ QString source = stream.readLine();
+ QString type = stream.readLine();
+ QString depends = stream.readLine();
+ QString mocable = stream.readLine();
+ stream.skipWhiteSpace();
+
+ QMakeLocalFileName fn(source);
+ QFileInfo fi = findFileInfo(fn);
+
+ SourceFile *file = files->lookupFile(fn);
+ if(!file) {
+ file = new SourceFile;
+ file->file = fn;
+ files->addFile(file);
+ file->type = (SourceFileType)type.toInt();
+ file->exists = fi.exists();
+ }
+ if(fi.exists() && fi.lastModified() < cache_fi.lastModified()) {
+ if(!file->dep_checked) { //get depends
+ if(!file->deps)
+ file->deps = new SourceDependChildren;
+ file->dep_checked = true;
+ QStringList depend_list = depends.split(";", QString::SkipEmptyParts);
+ for(int depend = 0; depend < depend_list.size(); ++depend) {
+ QMakeLocalFileName dep_fn(depend_list.at(depend));
+ QFileInfo dep_fi(findFileInfo(dep_fn));
+ SourceFile *dep = files->lookupFile(dep_fn);
+ if(!dep) {
+ dep = new SourceFile;
+ dep->file = dep_fn;
+ dep->exists = dep_fi.exists();
+ dep->type = QMakeSourceFileInfo::TYPE_UNKNOWN;
+ files->addFile(dep);
+ }
+ dep->included_count++;
+ file->deps->addChild(dep);
+ }
+ }
+ if(!file->moc_checked) { //get mocs
+ file->moc_checked = true;
+ file->mocable = mocable.toInt();
+ }
+ }
+ }
+ }
+ }
+#endif
+}
+
+QMap<QString, QStringList> QMakeSourceFileInfo::getCacheVerification()
+{
+ return QMap<QString, QStringList>();
+}
+
+bool QMakeSourceFileInfo::verifyCache(const QMap<QString, QStringList> &v)
+{
+ return v == getCacheVerification();
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/makefiledeps.h b/qmake/generators/makefiledeps.h
new file mode 100644
index 0000000000..c3f8770797
--- /dev/null
+++ b/qmake/generators/makefiledeps.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAKEFILEDEPS_H
+#define MAKEFILEDEPS_H
+
+#include <qstringlist.h>
+#include <qfileinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+struct SourceFile;
+struct SourceDependChildren;
+class SourceFiles;
+
+class QMakeLocalFileName {
+ uint is_null : 1;
+ mutable QString real_name, local_name;
+public:
+ QMakeLocalFileName() : is_null(1) { }
+ QMakeLocalFileName(const QString &);
+ bool isNull() const { return is_null; }
+ inline const QString &real() const { return real_name; }
+ const QString &local() const;
+
+ bool operator==(const QMakeLocalFileName &other) {
+ return (this->real_name == other.real_name);
+ }
+ bool operator!=(const QMakeLocalFileName &other) {
+ return !(*this == other);
+ }
+};
+
+class QMakeSourceFileInfo
+{
+private:
+ //quick project lookups
+ SourceFiles *files, *includes;
+ bool files_changed;
+ QList<QMakeLocalFileName> depdirs;
+
+ //sleezy buffer code
+ char *spare_buffer;
+ int spare_buffer_size;
+ char *getBuffer(int s);
+
+ //actual guts
+ bool findMocs(SourceFile *);
+ bool findDeps(SourceFile *);
+ void dependTreeWalker(SourceFile *, SourceDependChildren *);
+
+ //cache
+ QString cachefile;
+
+protected:
+ virtual QMakeLocalFileName fixPathForFile(const QMakeLocalFileName &, bool forOpen=false);
+ virtual QMakeLocalFileName findFileForDep(const QMakeLocalFileName &, const QMakeLocalFileName &);
+ virtual QFileInfo findFileInfo(const QMakeLocalFileName &);
+
+public:
+ QMakeSourceFileInfo(const QString &cachefile="");
+ virtual ~QMakeSourceFileInfo();
+
+ QList<QMakeLocalFileName> dependencyPaths() const { return depdirs; }
+ void setDependencyPaths(const QList<QMakeLocalFileName> &);
+
+ enum DependencyMode { Recursive, NonRecursive };
+ inline void setDependencyMode(DependencyMode mode) { dep_mode = mode; }
+ inline DependencyMode dependencyMode() const { return dep_mode; }
+
+ enum SourceFileType { TYPE_UNKNOWN, TYPE_C, TYPE_UI, TYPE_QRC };
+ enum SourceFileSeek { SEEK_DEPS=0x01, SEEK_MOCS=0x02 };
+ void addSourceFiles(const QStringList &, uchar seek, SourceFileType type=TYPE_C);
+ void addSourceFile(const QString &, uchar seek, SourceFileType type=TYPE_C);
+ bool containsSourceFile(const QString &, SourceFileType type=TYPE_C);
+
+ int included(const QString &file);
+ QStringList dependencies(const QString &file);
+
+ bool mocable(const QString &file);
+
+ virtual QMap<QString, QStringList> getCacheVerification();
+ virtual bool verifyCache(const QMap<QString, QStringList> &);
+ void setCacheFile(const QString &cachefile); //auto caching
+ void loadCache(const QString &cf);
+ void saveCache(const QString &cf);
+
+private:
+ DependencyMode dep_mode;
+};
+
+QT_END_NAMESPACE
+
+#endif // MAKEFILEDEPS_H
diff --git a/qmake/generators/metamakefile.cpp b/qmake/generators/metamakefile.cpp
new file mode 100644
index 0000000000..a3fba6ab55
--- /dev/null
+++ b/qmake/generators/metamakefile.cpp
@@ -0,0 +1,572 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "metamakefile.h"
+#include "qregexp.h"
+#include "qdir.h"
+#include "qdebug.h"
+#include "makefile.h"
+#include "project.h"
+#include "cachekeys.h"
+
+#define BUILDSMETATYPE 1
+#define SUBDIRSMETATYPE 2
+
+QT_BEGIN_NAMESPACE
+
+MetaMakefileGenerator::~MetaMakefileGenerator()
+{
+ if(own_project)
+ delete project;
+}
+
+#ifndef QT_QMAKE_PARSER_ONLY
+
+class BuildsMetaMakefileGenerator : public MetaMakefileGenerator
+{
+private:
+ bool init_flag;
+ struct Build {
+ QString name, build;
+ MakefileGenerator *makefile;
+ };
+ QList<Build *> makefiles;
+ void clearBuilds();
+ MakefileGenerator *processBuild(const QString &);
+
+public:
+
+ BuildsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { }
+ virtual ~BuildsMetaMakefileGenerator() { clearBuilds(); }
+
+ virtual bool init();
+ virtual int type() const { return BUILDSMETATYPE; }
+ virtual bool write(const QString &);
+};
+
+void
+BuildsMetaMakefileGenerator::clearBuilds()
+{
+ for(int i = 0; i < makefiles.count(); i++) {
+ Build *build = makefiles[i];
+ if(QMakeProject *p = build->makefile->projectFile()) {
+ if(p != project)
+ delete p;
+ }
+ delete build->makefile;
+ delete build;
+ }
+ makefiles.clear();
+}
+
+bool
+BuildsMetaMakefileGenerator::init()
+{
+ if(init_flag)
+ return false;
+ init_flag = true;
+
+ const QStringList &builds = project->variables()["BUILDS"];
+ bool use_single_build = builds.isEmpty();
+ if(builds.count() > 1 && Option::output.fileName() == "-") {
+ use_single_build = true;
+ warn_msg(WarnLogic, "Cannot direct to stdout when using multiple BUILDS.");
+ } else if(0 && !use_single_build && project->first("TEMPLATE") == "subdirs") {
+ use_single_build = true;
+ warn_msg(WarnLogic, "Cannot specify multiple builds with TEMPLATE subdirs.");
+ }
+ if(!use_single_build) {
+ for(int i = 0; i < builds.count(); i++) {
+ QString build = builds[i];
+ MakefileGenerator *makefile = processBuild(build);
+ if(!makefile)
+ return false;
+ if(!makefile->supportsMetaBuild()) {
+ warn_msg(WarnLogic, "QMAKESPEC does not support multiple BUILDS.");
+ clearBuilds();
+ use_single_build = true;
+ break;
+ } else {
+ Build *b = new Build;
+ b->name = name;
+ if(builds.count() != 1)
+ b->build += build;
+ b->makefile = makefile;
+ makefiles += b;
+ }
+ }
+ }
+ if(use_single_build) {
+ Build *build = new Build;
+ build->name = name;
+ build->makefile = createMakefileGenerator(project, false);
+ if (build->makefile){
+ makefiles += build;
+ }else {
+ delete build;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+BuildsMetaMakefileGenerator::write(const QString &oldpwd)
+{
+ Build *glue = 0;
+ if(!makefiles.isEmpty() && !makefiles.first()->build.isNull()) {
+ glue = new Build;
+ glue->name = name;
+ glue->makefile = createMakefileGenerator(project, true);
+ makefiles += glue;
+ }
+
+ bool ret = true;
+ const QString &output_name = Option::output.fileName();
+ for(int i = 0; ret && i < makefiles.count(); i++) {
+ Option::output.setFileName(output_name);
+ Build *build = makefiles[i];
+
+ bool using_stdout = false;
+ if(build->makefile && (Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+ Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
+ && (!build->makefile->supportsMergedBuilds()
+ || (build->makefile->supportsMergedBuilds() && (!glue || build == glue)))) {
+ //open output
+ if(!(Option::output.isOpen())) {
+ if(Option::output.fileName() == "-") {
+ Option::output.setFileName("");
+ Option::output_dir = qmake_getpwd();
+ Option::output.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
+ using_stdout = true;
+ } else {
+ if(Option::output.fileName().isEmpty() &&
+ Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE)
+ Option::output.setFileName(project->first("QMAKE_MAKEFILE"));
+ Option::output_dir = oldpwd;
+ QString build_name = build->name;
+ if(!build->build.isEmpty()) {
+ if(!build_name.isEmpty())
+ build_name += ".";
+ build_name += build->build;
+ }
+ if(!build->makefile->openOutput(Option::output, build_name)) {
+ fprintf(stderr, "Failure to open file: %s\n",
+ Option::output.fileName().isEmpty() ? "(stdout)" :
+ Option::output.fileName().toLatin1().constData());
+ return false;
+ }
+ }
+ }
+ } else {
+ using_stdout = true; //kind of..
+ }
+
+ if(!build->makefile) {
+ ret = false;
+ } else if(build == glue) {
+ ret = build->makefile->writeProjectMakefile();
+ } else {
+ ret = build->makefile->write();
+ if (glue && glue->makefile->supportsMergedBuilds())
+ ret = glue->makefile->mergeBuildProject(build->makefile);
+ }
+ if(!using_stdout) {
+ Option::output.close();
+ if(!ret)
+ Option::output.remove();
+ }
+
+ // debugging
+ if(Option::debug_level) {
+ debug_msg(1, "Dumping all variables:");
+ QMap<QString, QStringList> &vars = project->variables();
+ for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) {
+ if(!it.key().startsWith(".") && !it.value().isEmpty())
+ debug_msg(1, "%s === %s", it.key().toLatin1().constData(),
+ it.value().join(" :: ").toLatin1().constData());
+ }
+ }
+ }
+ return ret;
+}
+
+MakefileGenerator
+*BuildsMetaMakefileGenerator::processBuild(const QString &build)
+{
+ if(project) {
+ debug_msg(1, "Meta Generator: Parsing '%s' for build [%s].",
+ project->projectFile().toLatin1().constData(),build.toLatin1().constData());
+
+ //initialize the base
+ QMap<QString, QStringList> basevars;
+ if(!project->isEmpty(build + ".CONFIG"))
+ basevars["CONFIG"] += project->values(build + ".CONFIG");
+ basevars["CONFIG"] += build;
+ basevars["CONFIG"] += "build_pass";
+ basevars["BUILD_PASS"] = QStringList(build);
+ QStringList buildname = project->values(build + ".name");
+ basevars["BUILD_NAME"] = (buildname.isEmpty() ? QStringList(build) : buildname);
+
+ //create project
+ QMakeProject *build_proj = new QMakeProject(project->properties(), basevars);
+
+ //all the user configs must be set again afterwards (for .pro tests and for .prf tests)
+ const QStringList old_after_user_config = Option::after_user_configs;
+ const QStringList old_user_config = Option::user_configs;
+ Option::after_user_configs += basevars["CONFIG"];
+ Option::user_configs += basevars["CONFIG"];
+ build_proj->read(project->projectFile());
+ Option::after_user_configs = old_after_user_config;
+ Option::user_configs = old_user_config;
+
+ //done
+ return createMakefileGenerator(build_proj);
+ }
+ return 0;
+}
+
+class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator
+{
+protected:
+ bool init_flag;
+ struct Subdir {
+ Subdir() : makefile(0), indent(0) { }
+ ~Subdir() { delete makefile; }
+ QString input_dir;
+ QString output_dir, output_file;
+ MetaMakefileGenerator *makefile;
+ int indent;
+ };
+ QList<Subdir *> subs;
+ MakefileGenerator *processBuild(const QString &);
+
+public:
+ SubdirsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { }
+ virtual ~SubdirsMetaMakefileGenerator();
+
+ virtual bool init();
+ virtual int type() const { return SUBDIRSMETATYPE; }
+ virtual bool write(const QString &);
+};
+
+bool
+SubdirsMetaMakefileGenerator::init()
+{
+ if(init_flag)
+ return false;
+ init_flag = true;
+ bool hasError = false;
+
+ // It might make sense to bequeath the CONFIG option to the recursed
+ // projects. OTOH, one would most likely have it in all projects anyway -
+ // either through a qmakespec, a .qmake.cache or explicitly - as otherwise
+ // running qmake in a subdirectory would have a different auto-recurse
+ // setting than in parent directories.
+ bool recurse = Option::recursive == Option::QMAKE_RECURSIVE_YES
+ || (Option::recursive == Option::QMAKE_RECURSIVE_DEFAULT
+ && project->isRecursive());
+ if(recurse) {
+ QString old_output_dir = Option::output_dir;
+ QString old_output = Option::output.fileName();
+ QString oldpwd = qmake_getpwd();
+ QString thispwd = oldpwd;
+ if(!thispwd.endsWith('/'))
+ thispwd += '/';
+ const QStringList &subdirs = project->values("SUBDIRS");
+ static int recurseDepth = -1;
+ ++recurseDepth;
+ for(int i = 0; i < subdirs.size(); ++i) {
+ Subdir *sub = new Subdir;
+ sub->indent = recurseDepth;
+
+ QFileInfo subdir(subdirs.at(i));
+ if(!project->isEmpty(subdirs.at(i) + ".file"))
+ subdir = project->first(subdirs.at(i) + ".file");
+ else if(!project->isEmpty(subdirs.at(i) + ".subdir"))
+ subdir = project->first(subdirs.at(i) + ".subdir");
+ QString sub_name;
+ if(subdir.isDir())
+ subdir = QFileInfo(subdir.filePath() + "/" + subdir.fileName() + Option::pro_ext);
+ else
+ sub_name = subdir.baseName();
+ if(!subdir.isRelative()) { //we can try to make it relative
+ QString subdir_path = subdir.filePath();
+ if(subdir_path.startsWith(thispwd))
+ subdir = QFileInfo(subdir_path.mid(thispwd.length()));
+ }
+
+ //handle sub project
+ QMakeProject *sub_proj = new QMakeProject(project->properties());
+ for (int ind = 0; ind < sub->indent; ++ind)
+ printf(" ");
+ sub->input_dir = subdir.absolutePath();
+ if(subdir.isRelative() && old_output_dir != oldpwd) {
+ sub->output_dir = old_output_dir + "/" + subdir.path();
+ printf("Reading %s [%s]\n", subdir.absoluteFilePath().toLatin1().constData(), sub->output_dir.toLatin1().constData());
+ } else { //what about shadow builds?
+ sub->output_dir = sub->input_dir;
+ printf("Reading %s\n", subdir.absoluteFilePath().toLatin1().constData());
+ }
+ qmake_setpwd(sub->input_dir);
+ Option::output_dir = sub->output_dir;
+ bool tmpError = !sub_proj->read(subdir.fileName());
+ if(!sub_proj->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) {
+ fprintf(stderr, "Project file(%s) not recursed because all requirements not met:\n\t%s\n",
+ subdir.fileName().toLatin1().constData(),
+ sub_proj->values("QMAKE_FAILED_REQUIREMENTS").join(" ").toLatin1().constData());
+ delete sub;
+ delete sub_proj;
+ Option::output_dir = old_output_dir;
+ qmake_setpwd(oldpwd);
+ continue;
+ } else {
+ hasError |= tmpError;
+ }
+ sub->makefile = MetaMakefileGenerator::createMetaGenerator(sub_proj, sub_name);
+ if(0 && sub->makefile->type() == SUBDIRSMETATYPE) {
+ subs.append(sub);
+ } else {
+ const QString output_name = Option::output.fileName();
+ Option::output.setFileName(sub->output_file);
+ hasError |= !sub->makefile->write(sub->output_dir);
+ delete sub;
+ qmakeClearCaches();
+ sub = 0;
+ Option::output.setFileName(output_name);
+ }
+ Option::output_dir = old_output_dir;
+ qmake_setpwd(oldpwd);
+
+ }
+ --recurseDepth;
+ Option::output.setFileName(old_output);
+ Option::output_dir = old_output_dir;
+ qmake_setpwd(oldpwd);
+ }
+
+ Subdir *self = new Subdir;
+ self->input_dir = qmake_getpwd();
+ self->output_dir = Option::output_dir;
+ if(!recurse || (!Option::output.fileName().endsWith(Option::dir_sep) && !QFileInfo(Option::output).isDir()))
+ self->output_file = Option::output.fileName();
+ self->makefile = new BuildsMetaMakefileGenerator(project, name, false);
+ self->makefile->init();
+ subs.append(self);
+
+ return !hasError;
+}
+
+bool
+SubdirsMetaMakefileGenerator::write(const QString &oldpwd)
+{
+ bool ret = true;
+ const QString &pwd = qmake_getpwd();
+ const QString &output_dir = Option::output_dir;
+ const QString &output_name = Option::output.fileName();
+ for(int i = 0; ret && i < subs.count(); i++) {
+ const Subdir *sub = subs.at(i);
+ qmake_setpwd(subs.at(i)->input_dir);
+ Option::output_dir = QFileInfo(subs.at(i)->output_dir).absoluteFilePath();
+ if(Option::output_dir.at(Option::output_dir.length()-1) != QLatin1Char('/'))
+ Option::output_dir += QLatin1Char('/');
+ Option::output.setFileName(subs.at(i)->output_file);
+ if(i != subs.count()-1) {
+ for (int ind = 0; ind < sub->indent; ++ind)
+ printf(" ");
+ printf("Writing %s\n", QDir::cleanPath(Option::output_dir+"/"+
+ Option::output.fileName()).toLatin1().constData());
+ }
+ QString writepwd = Option::fixPathToLocalOS(qmake_getpwd());
+ if(!writepwd.startsWith(Option::fixPathToLocalOS(oldpwd)))
+ writepwd = oldpwd;
+ if(!(ret = subs.at(i)->makefile->write(writepwd)))
+ break;
+ //restore because I'm paranoid
+ qmake_setpwd(pwd);
+ Option::output.setFileName(output_name);
+ Option::output_dir = output_dir;
+ }
+ return ret;
+}
+
+SubdirsMetaMakefileGenerator::~SubdirsMetaMakefileGenerator()
+{
+ for(int i = 0; i < subs.count(); i++)
+ delete subs[i];
+ subs.clear();
+}
+
+//Factory things
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "unixmake.h"
+#include "mingw_make.h"
+#include "projectgenerator.h"
+#include "pbuilder_pbx.h"
+#include "msvc_nmake.h"
+#include "borland_bmake.h"
+#include "msvc_vcproj.h"
+#include "msvc_vcxproj.h"
+#include "symmake_abld.h"
+#include "symmake_sbsv2.h"
+#include "symbian_makefile.h"
+#include "gbuild.h"
+QT_END_INCLUDE_NAMESPACE
+
+MakefileGenerator *
+MetaMakefileGenerator::createMakefileGenerator(QMakeProject *proj, bool noIO)
+{
+ MakefileGenerator *mkfile = NULL;
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
+ mkfile = new ProjectGenerator;
+ mkfile->setProjectFile(proj);
+ return mkfile;
+ }
+
+ QString gen = proj->first("MAKEFILE_GENERATOR");
+ if(gen.isEmpty()) {
+ fprintf(stderr, "MAKEFILE_GENERATOR variable not set as a result of parsing : %s. Possibly qmake was not able to find files included using \"include(..)\" - enable qmake debugging to investigate more.\n",
+ proj->projectFile().toLatin1().constData());
+ } else if(gen == "UNIX") {
+ mkfile = new UnixMakefileGenerator;
+ } else if(gen == "MINGW") {
+ mkfile = new MingwMakefileGenerator;
+ } else if(gen == "PROJECTBUILDER" || gen == "XCODE") {
+ mkfile = new ProjectBuilderMakefileGenerator;
+ } else if(gen == "MSVC.NET") {
+ if (proj->first("TEMPLATE").startsWith("vc"))
+ mkfile = new VcprojGenerator;
+ else
+ mkfile = new NmakeMakefileGenerator;
+ } else if(gen == "MSBUILD") {
+ // Visual Studio >= v11.0
+ if (proj->first("TEMPLATE").startsWith("vc"))
+ mkfile = new VcxprojGenerator;
+ else
+ mkfile = new NmakeMakefileGenerator;
+ } else if(gen == "BMAKE") {
+ mkfile = new BorlandMakefileGenerator;
+ } else if(gen == "SYMBIAN_ABLD") {
+ mkfile = new SymbianAbldMakefileGenerator;
+ } else if(gen == "SYMBIAN_SBSV2") {
+ mkfile = new SymbianSbsv2MakefileGenerator;
+ } else if(gen == "SYMBIAN_UNIX") {
+ mkfile = new SymbianMakefileTemplate<UnixMakefileGenerator>;
+ } else if(gen == "SYMBIAN_MINGW") {
+ mkfile = new SymbianMakefileTemplate<MingwMakefileGenerator>;
+ } else if(gen == "GBUILD") {
+ mkfile = new GBuildMakefileGenerator;
+ } else {
+ fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData());
+ }
+ if (mkfile) {
+ mkfile->setNoIO(noIO);
+ mkfile->setProjectFile(proj);
+ }
+ return mkfile;
+}
+
+MetaMakefileGenerator *
+MetaMakefileGenerator::createMetaGenerator(QMakeProject *proj, const QString &name, bool op, bool *success)
+{
+ MetaMakefileGenerator *ret = 0;
+ if ((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+ Option::qmake_mode == Option::QMAKE_GENERATE_PRL)) {
+ if (proj->first("TEMPLATE").endsWith("subdirs"))
+ ret = new SubdirsMetaMakefileGenerator(proj, name, op);
+ }
+ if (!ret)
+ ret = new BuildsMetaMakefileGenerator(proj, name, op);
+ bool res = ret->init();
+ if (success)
+ *success = res;
+ return ret;
+}
+
+#endif // QT_QMAKE_PARSER_ONLY
+
+bool
+MetaMakefileGenerator::modesForGenerator(const QString &gen,
+ Option::HOST_MODE *host_mode, Option::TARG_MODE *target_mode)
+{
+ if (gen == "UNIX") {
+#ifdef Q_OS_MAC
+ *host_mode = Option::HOST_MACX_MODE;
+ *target_mode = Option::TARG_MACX_MODE;
+#else
+ *host_mode = Option::HOST_UNIX_MODE;
+ *target_mode = Option::TARG_UNIX_MODE;
+#endif
+ } else if (gen == "MSVC.NET" || gen == "BMAKE" || gen == "MSBUILD") {
+ *host_mode = Option::HOST_WIN_MODE;
+ *target_mode = Option::TARG_WIN_MODE;
+ } else if (gen == "MINGW") {
+#if defined(Q_OS_MAC)
+ *host_mode = Option::HOST_MACX_MODE;
+#elif defined(Q_OS_UNIX)
+ *host_mode = Option::HOST_UNIX_MODE;
+#else
+ *host_mode = Option::HOST_WIN_MODE;
+#endif
+ *target_mode = Option::TARG_WIN_MODE;
+ } else if (gen == "PROJECTBUILDER" || gen == "XCODE") {
+ *host_mode = Option::HOST_MACX_MODE;
+ *target_mode = Option::TARG_MACX_MODE;
+ } else if (gen == "SYMBIAN_ABLD" || gen == "SYMBIAN_SBSV2" || gen == "SYMBIAN_UNIX" || gen == "SYMBIAN_MINGW") {
+#if defined(Q_OS_MAC)
+ *host_mode = Option::HOST_MACX_MODE;
+#elif defined(Q_OS_UNIX)
+ *host_mode = Option::HOST_UNIX_MODE;
+#else
+ *host_mode = Option::HOST_WIN_MODE;
+#endif
+ *target_mode = Option::TARG_SYMBIAN_MODE;
+ } else if (gen == "GBUILD") {
+ *host_mode = Option::HOST_UNIX_MODE;
+ *target_mode = Option::TARG_INTEGRITY_MODE;
+ } else {
+ fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData());
+ return false;
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/metamakefile.h b/qmake/generators/metamakefile.h
new file mode 100644
index 0000000000..c8592d3afc
--- /dev/null
+++ b/qmake/generators/metamakefile.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef METAMAKEFILE_H
+#define METAMAKEFILE_H
+
+#include <option.h>
+
+#include <qlist.h>
+#include <qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMakeProject;
+class MakefileGenerator;
+
+class MetaMakefileGenerator
+{
+protected:
+ MetaMakefileGenerator(QMakeProject *p, const QString &n, bool op=true) : project(p), own_project(op), name(n) { }
+ QMakeProject *project;
+ bool own_project;
+ QString name;
+
+public:
+
+ virtual ~MetaMakefileGenerator();
+
+ static MetaMakefileGenerator *createMetaGenerator(QMakeProject *proj, const QString &name, bool op=true, bool *success = 0);
+ static MakefileGenerator *createMakefileGenerator(QMakeProject *proj, bool noIO = false);
+
+ static bool modesForGenerator(const QString &generator,
+ Option::HOST_MODE *host_mode, Option::TARG_MODE *target_mode);
+
+ inline QMakeProject *projectFile() const { return project; }
+
+ virtual bool init() = 0;
+ virtual int type() const { return -1; }
+ virtual bool write(const QString &oldpwd) = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // METAMAKEFILE_H
diff --git a/qmake/generators/projectgenerator.cpp b/qmake/generators/projectgenerator.cpp
new file mode 100644
index 0000000000..da634a1179
--- /dev/null
+++ b/qmake/generators/projectgenerator.cpp
@@ -0,0 +1,511 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "projectgenerator.h"
+#include "option.h"
+#include <qdatetime.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+
+QT_BEGIN_NAMESPACE
+
+QString project_builtin_regx() //calculate the builtin regular expression..
+{
+ QString ret;
+ QStringList builtin_exts;
+ builtin_exts << Option::c_ext << Option::ui_ext << Option::yacc_ext << Option::lex_ext << ".ts" << ".xlf" << ".qrc";
+ builtin_exts += Option::h_ext + Option::cpp_ext;
+ for(int i = 0; i < builtin_exts.size(); ++i) {
+ if(!ret.isEmpty())
+ ret += "; ";
+ ret += QString("*") + builtin_exts[i];
+ }
+ return ret;
+}
+
+ProjectGenerator::ProjectGenerator() : MakefileGenerator(), init_flag(false)
+{
+}
+
+void
+ProjectGenerator::init()
+{
+ if(init_flag)
+ return;
+ int file_count = 0;
+ init_flag = true;
+ verifyCompilers();
+
+ project->read(QMakeProject::ReadFeatures);
+ project->variables()["CONFIG"].clear();
+
+ QMap<QString, QStringList> &v = project->variables();
+ QString templ = Option::user_template.isEmpty() ? QString("app") : Option::user_template;
+ if(!Option::user_template_prefix.isEmpty())
+ templ.prepend(Option::user_template_prefix);
+ v["TEMPLATE_ASSIGN"] += templ;
+
+ //figure out target
+ if(Option::output.fileName() == "-")
+ v["TARGET_ASSIGN"] = QStringList("unknown");
+ else
+ v["TARGET_ASSIGN"] = QStringList(QFileInfo(Option::output).baseName());
+
+ //the scary stuff
+ if(project->first("TEMPLATE_ASSIGN") != "subdirs") {
+ QString builtin_regex = project_builtin_regx();
+ QStringList dirs = Option::projfile::project_dirs;
+ if(Option::projfile::do_pwd) {
+ if(!v["INCLUDEPATH"].contains("."))
+ v["INCLUDEPATH"] += ".";
+ dirs.prepend(qmake_getpwd());
+ }
+
+ for(int i = 0; i < dirs.count(); ++i) {
+ QString dir, regex, pd = dirs.at(i);
+ bool add_depend = false;
+ if(exists(pd)) {
+ QFileInfo fi(fileInfo(pd));
+ if(fi.isDir()) {
+ dir = pd;
+ add_depend = true;
+ if(dir.right(1) != Option::dir_sep)
+ dir += Option::dir_sep;
+ if(Option::recursive == Option::QMAKE_RECURSIVE_YES) {
+ QStringList files = QDir(dir).entryList(QDir::Files);
+ for(int i = 0; i < (int)files.count(); i++) {
+ if(files[i] != "." && files[i] != "..")
+ dirs.append(dir + files[i] + QDir::separator() + builtin_regex);
+ }
+ }
+ regex = builtin_regex;
+ } else {
+ QString file = pd;
+ int s = file.lastIndexOf(Option::dir_sep);
+ if(s != -1)
+ dir = file.left(s+1);
+ if(addFile(file)) {
+ add_depend = true;
+ file_count++;
+ }
+ }
+ } else { //regexp
+ regex = pd;
+ }
+ if(!regex.isEmpty()) {
+ int s = regex.lastIndexOf(Option::dir_sep);
+ if(s != -1) {
+ dir = regex.left(s+1);
+ regex = regex.right(regex.length() - (s+1));
+ }
+ if(Option::recursive == Option::QMAKE_RECURSIVE_YES) {
+ QStringList entries = QDir(dir).entryList(QDir::Dirs);
+ for(int i = 0; i < (int)entries.count(); i++) {
+ if(entries[i] != "." && entries[i] != "..") {
+ dirs.append(dir + entries[i] + QDir::separator() + regex);
+ }
+ }
+ }
+ QStringList files = QDir(dir).entryList(QDir::nameFiltersFromString(regex));
+ for(int i = 0; i < (int)files.count(); i++) {
+ QString file = dir + files[i];
+ if (addFile(file)) {
+ add_depend = true;
+ file_count++;
+ }
+ }
+ }
+ if(add_depend && !dir.isEmpty() && !v["DEPENDPATH"].contains(dir, Qt::CaseInsensitive)) {
+ QFileInfo fi(fileInfo(dir));
+ if(fi.absoluteFilePath() != qmake_getpwd())
+ v["DEPENDPATH"] += fileFixify(dir);
+ }
+ }
+ }
+ if(!file_count) { //shall we try a subdir?
+ QStringList knownDirs = Option::projfile::project_dirs;
+ if(Option::projfile::do_pwd)
+ knownDirs.prepend(".");
+ const QString out_file = fileFixify(Option::output.fileName());
+ for(int i = 0; i < knownDirs.count(); ++i) {
+ QString pd = knownDirs.at(i);
+ if(exists(pd)) {
+ QString newdir = pd;
+ QFileInfo fi(fileInfo(newdir));
+ if(fi.isDir()) {
+ newdir = fileFixify(newdir);
+ QStringList &subdirs = v["SUBDIRS"];
+ if(exists(fi.filePath() + QDir::separator() + fi.fileName() + Option::pro_ext) &&
+ !subdirs.contains(newdir, Qt::CaseInsensitive)) {
+ subdirs.append(newdir);
+ } else {
+ QStringList profiles = QDir(newdir).entryList(QStringList("*" + Option::pro_ext), QDir::Files);
+ for(int i = 0; i < (int)profiles.count(); i++) {
+ QString nd = newdir;
+ if(nd == ".")
+ nd = "";
+ else if(!nd.isEmpty() && !nd.endsWith(QString(QChar(QDir::separator()))))
+ nd += QDir::separator();
+ nd += profiles[i];
+ fileFixify(nd);
+ if(profiles[i] != "." && profiles[i] != ".." &&
+ !subdirs.contains(nd, Qt::CaseInsensitive) && !out_file.endsWith(nd))
+ subdirs.append(nd);
+ }
+ }
+ if(Option::recursive == Option::QMAKE_RECURSIVE_YES) {
+ QStringList dirs = QDir(newdir).entryList(QDir::Dirs);
+ for(int i = 0; i < (int)dirs.count(); i++) {
+ QString nd = fileFixify(newdir + QDir::separator() + dirs[i]);
+ if(dirs[i] != "." && dirs[i] != ".." && !knownDirs.contains(nd, Qt::CaseInsensitive))
+ knownDirs.append(nd);
+ }
+ }
+ }
+ } else { //regexp
+ QString regx = pd, dir;
+ int s = regx.lastIndexOf(Option::dir_sep);
+ if(s != -1) {
+ dir = regx.left(s+1);
+ regx = regx.right(regx.length() - (s+1));
+ }
+ QStringList files = QDir(dir).entryList(QDir::nameFiltersFromString(regx), QDir::Dirs);
+ QStringList &subdirs = v["SUBDIRS"];
+ for(int i = 0; i < (int)files.count(); i++) {
+ QString newdir(dir + files[i]);
+ QFileInfo fi(fileInfo(newdir));
+ if(fi.fileName() != "." && fi.fileName() != "..") {
+ newdir = fileFixify(newdir);
+ if(exists(fi.filePath() + QDir::separator() + fi.fileName() + Option::pro_ext) &&
+ !subdirs.contains(newdir)) {
+ subdirs.append(newdir);
+ } else {
+ QStringList profiles = QDir(newdir).entryList(QStringList("*" + Option::pro_ext), QDir::Files);
+ for(int i = 0; i < (int)profiles.count(); i++) {
+ QString nd = newdir + QDir::separator() + files[i];
+ fileFixify(nd);
+ if(files[i] != "." && files[i] != ".." && !subdirs.contains(nd, Qt::CaseInsensitive)) {
+ if(newdir + files[i] != Option::output_dir + Option::output.fileName())
+ subdirs.append(nd);
+ }
+ }
+ }
+ if(Option::recursive == Option::QMAKE_RECURSIVE_YES
+ && !knownDirs.contains(newdir, Qt::CaseInsensitive))
+ knownDirs.append(newdir);
+ }
+ }
+ }
+ }
+ v["TEMPLATE_ASSIGN"] = QStringList("subdirs");
+ return;
+ }
+
+ //setup deplist
+ QList<QMakeLocalFileName> deplist;
+ {
+ const QStringList &d = v["DEPENDPATH"];
+ for(int i = 0; i < d.size(); ++i)
+ deplist.append(QMakeLocalFileName(d[i]));
+ }
+ setDependencyPaths(deplist);
+
+ QStringList &h = v["HEADERS"];
+ bool no_qt_files = true;
+ QString srcs[] = { "SOURCES", "YACCSOURCES", "LEXSOURCES", "FORMS", QString() };
+ for(int i = 0; !srcs[i].isNull(); i++) {
+ const QStringList &l = v[srcs[i]];
+ QMakeSourceFileInfo::SourceFileType type = QMakeSourceFileInfo::TYPE_C;
+ QMakeSourceFileInfo::addSourceFiles(l, QMakeSourceFileInfo::SEEK_DEPS, type);
+ for(int i = 0; i < l.size(); ++i) {
+ QStringList tmp = QMakeSourceFileInfo::dependencies(l[i]);
+ if(!tmp.isEmpty()) {
+ for(int dep_it = 0; dep_it < tmp.size(); ++dep_it) {
+ QString dep = tmp[dep_it];
+ dep = fixPathToQmake(dep);
+ QString file_dir = dep.section(Option::dir_sep, 0, -2),
+ file_no_path = dep.section(Option::dir_sep, -1);
+ if(!file_dir.isEmpty()) {
+ for(int inc_it = 0; inc_it < deplist.size(); ++inc_it) {
+ QMakeLocalFileName inc = deplist[inc_it];
+ if(inc.local() == file_dir && !v["INCLUDEPATH"].contains(inc.real(), Qt::CaseInsensitive))
+ v["INCLUDEPATH"] += inc.real();
+ }
+ }
+ if(no_qt_files && file_no_path.indexOf(QRegExp("^q[a-z_0-9].h$")) != -1)
+ no_qt_files = false;
+ QString h_ext;
+ for(int hit = 0; hit < Option::h_ext.size(); ++hit) {
+ if(dep.endsWith(Option::h_ext.at(hit))) {
+ h_ext = Option::h_ext.at(hit);
+ break;
+ }
+ }
+ if(!h_ext.isEmpty()) {
+ for(int cppit = 0; cppit < Option::cpp_ext.size(); ++cppit) {
+ QString src(dep.left(dep.length() - h_ext.length()) +
+ Option::cpp_ext.at(cppit));
+ if(exists(src)) {
+ QStringList &srcl = v["SOURCES"];
+ if(!srcl.contains(src, Qt::CaseInsensitive))
+ srcl.append(src);
+ }
+ }
+ } else if(dep.endsWith(Option::lex_ext) &&
+ file_no_path.startsWith(Option::lex_mod)) {
+ addConfig("lex_included");
+ }
+ if(!h.contains(dep, Qt::CaseInsensitive))
+ h += dep;
+ }
+ }
+ }
+ }
+
+ //strip out files that are actually output from internal compilers (ie temporary files)
+ const QStringList &quc = project->variables()["QMAKE_EXTRA_COMPILERS"];
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = project->variables()[(*it) + ".output"].first();
+ if(tmp_out.isEmpty())
+ continue;
+
+ QStringList var_out = project->variables()[(*it) + ".variable_out"];
+ bool defaults = var_out.isEmpty();
+ for(int i = 0; i < var_out.size(); ++i) {
+ QString v = var_out.at(i);
+ if(v.startsWith("GENERATED_")) {
+ defaults = true;
+ break;
+ }
+ }
+ if(defaults) {
+ var_out << "SOURCES";
+ var_out << "HEADERS";
+ var_out << "FORMS";
+ }
+ const QStringList &tmp = project->variables()[(*it) + ".input"];
+ for(QStringList::ConstIterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
+ QStringList &inputs = project->variables()[(*it2)];
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
+ QString path = replaceExtraCompilerVariables(tmp_out, (*input), QString());
+ path = fixPathToQmake(path).section('/', -1);
+ for(int i = 0; i < var_out.size(); ++i) {
+ QString v = var_out.at(i);
+ QStringList &list = project->variables()[v];
+ for(int src = 0; src < list.size(); ) {
+ if(list[src] == path || list[src].endsWith("/" + path))
+ list.removeAt(src);
+ else
+ ++src;
+ }
+ }
+ }
+ }
+ }
+}
+
+bool
+ProjectGenerator::writeMakefile(QTextStream &t)
+{
+ t << "######################################################################" << endl;
+ t << "# Automatically generated by qmake (" << qmake_version() << ") " << QDateTime::currentDateTime().toString() << endl;
+ t << "######################################################################" << endl << endl;
+ if(!Option::user_configs.isEmpty())
+ t << "CONFIG += " << Option::user_configs.join(" ") << endl;
+ int i;
+ for(i = 0; i < Option::before_user_vars.size(); ++i)
+ t << Option::before_user_vars[i] << endl;
+ t << getWritableVar("TEMPLATE_ASSIGN", false);
+ if(project->first("TEMPLATE_ASSIGN") == "subdirs") {
+ t << endl << "# Directories" << "\n"
+ << getWritableVar("SUBDIRS");
+ } else {
+ t << getWritableVar("TARGET_ASSIGN")
+ << getWritableVar("CONFIG", false)
+ << getWritableVar("CONFIG_REMOVE", false)
+ << getWritableVar("DEPENDPATH")
+ << getWritableVar("INCLUDEPATH") << endl;
+
+ t << "# Input" << "\n";
+ t << getWritableVar("HEADERS")
+ << getWritableVar("FORMS")
+ << getWritableVar("LEXSOURCES")
+ << getWritableVar("YACCSOURCES")
+ << getWritableVar("SOURCES")
+ << getWritableVar("RESOURCES")
+ << getWritableVar("TRANSLATIONS");
+ }
+ for(i = 0; i < Option::after_user_vars.size(); ++i)
+ t << Option::after_user_vars[i] << endl;
+ return true;
+}
+
+bool
+ProjectGenerator::addConfig(const QString &cfg, bool add)
+{
+ QString where = "CONFIG";
+ if(!add)
+ where = "CONFIG_REMOVE";
+ if(!project->variables()[where].contains(cfg)) {
+ project->variables()[where] += cfg;
+ return true;
+ }
+ return false;
+}
+
+bool
+ProjectGenerator::addFile(QString file)
+{
+ file = fileFixify(file, qmake_getpwd());
+ QString dir;
+ int s = file.lastIndexOf(Option::dir_sep);
+ if(s != -1)
+ dir = file.left(s+1);
+ if(file.mid(dir.length(), Option::h_moc_mod.length()) == Option::h_moc_mod)
+ return false;
+
+ QString where;
+ for(int cppit = 0; cppit < Option::cpp_ext.size(); ++cppit) {
+ if(file.endsWith(Option::cpp_ext[cppit])) {
+ where = "SOURCES";
+ break;
+ }
+ }
+ if(where.isEmpty()) {
+ for(int hit = 0; hit < Option::h_ext.size(); ++hit)
+ if(file.endsWith(Option::h_ext.at(hit))) {
+ where = "HEADERS";
+ break;
+ }
+ }
+ if(where.isEmpty()) {
+ for(int cit = 0; cit < Option::c_ext.size(); ++cit) {
+ if(file.endsWith(Option::c_ext[cit])) {
+ where = "SOURCES";
+ break;
+ }
+ }
+ }
+ if(where.isEmpty()) {
+ if(file.endsWith(Option::ui_ext))
+ where = "FORMS";
+ else if(file.endsWith(Option::lex_ext))
+ where = "LEXSOURCES";
+ else if(file.endsWith(Option::yacc_ext))
+ where = "YACCSOURCES";
+ else if(file.endsWith(".ts") || file.endsWith(".xlf"))
+ where = "TRANSLATIONS";
+ else if(file.endsWith(".qrc"))
+ where = "RESOURCES";
+ }
+
+ QString newfile = fixPathToQmake(fileFixify(file));
+
+ QStringList &endList = project->variables()[where];
+ if(!endList.contains(newfile, Qt::CaseInsensitive)) {
+ endList += newfile;
+ return true;
+ }
+ return false;
+}
+
+QString
+ProjectGenerator::getWritableVar(const QString &v, bool)
+{
+ QStringList &vals = project->variables()[v];
+ if(vals.isEmpty())
+ return "";
+
+ // If values contain spaces, ensure that they are quoted
+ for(QStringList::iterator it = vals.begin(); it != vals.end(); ++it) {
+ if ((*it).contains(' ') && !(*it).startsWith(' '))
+ *it = '\"' + *it + '\"';
+ }
+
+ QString ret;
+ if(v.endsWith("_REMOVE"))
+ ret = v.left(v.length() - 7) + " -= ";
+ else if(v.endsWith("_ASSIGN"))
+ ret = v.left(v.length() - 7) + " = ";
+ else
+ ret = v + " += ";
+ QString join = vals.join(" ");
+ if(ret.length() + join.length() > 80) {
+ QString spaces;
+ for(int i = 0; i < ret.length(); i++)
+ spaces += " ";
+ join = vals.join(" \\\n" + spaces);
+ }
+ return ret + join + "\n";
+}
+
+bool
+ProjectGenerator::openOutput(QFile &file, const QString &build) const
+{
+ QString outdir;
+ if(!file.fileName().isEmpty()) {
+ QFileInfo fi(fileInfo(file.fileName()));
+ if(fi.isDir())
+ outdir = fi.path() + QDir::separator();
+ }
+ if(!outdir.isEmpty() || file.fileName().isEmpty()) {
+ QString dir = qmake_getpwd();
+ int s = dir.lastIndexOf('/');
+ if(s != -1)
+ dir = dir.right(dir.length() - (s + 1));
+ file.setFileName(outdir + dir + Option::pro_ext);
+ }
+ return MakefileGenerator::openOutput(file, build);
+}
+
+
+QString
+ProjectGenerator::fixPathToQmake(const QString &file)
+{
+ QString ret = file;
+ if(Option::dir_sep != QLatin1String("/"))
+ ret = ret.replace(Option::dir_sep, QLatin1String("/"));
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/projectgenerator.h b/qmake/generators/projectgenerator.h
new file mode 100644
index 0000000000..7b4d56c3cd
--- /dev/null
+++ b/qmake/generators/projectgenerator.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROJECTGENERATOR_H
+#define PROJECTGENERATOR_H
+
+#include "makefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class ProjectGenerator : public MakefileGenerator
+{
+ bool init_flag;
+ bool addFile(QString);
+ bool addConfig(const QString &, bool add=true);
+ QString getWritableVar(const QString &, bool fixPath=true);
+ QString fixPathToQmake(const QString &file);
+protected:
+ virtual void init();
+ virtual bool writeMakefile(QTextStream &);
+public:
+ ProjectGenerator();
+ ~ProjectGenerator();
+ virtual bool supportsMetaBuild() { return false; }
+ virtual bool openOutput(QFile &, const QString &) const;
+};
+
+inline ProjectGenerator::~ProjectGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // PROJECTGENERATOR_H
diff --git a/qmake/generators/symbian/initprojectdeploy_symbian.cpp b/qmake/generators/symbian/initprojectdeploy_symbian.cpp
new file mode 100644
index 0000000000..8d04a424c6
--- /dev/null
+++ b/qmake/generators/symbian/initprojectdeploy_symbian.cpp
@@ -0,0 +1,379 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "initprojectdeploy_symbian.h"
+#include <QDirIterator>
+#include <project.h>
+#include <qxmlstream.h>
+#include <qsettings.h>
+#include <qdebug.h>
+
+// Included from tools/shared
+#include <symbian/epocroot_p.h>
+
+#define SYSBIN_DIR "/sys/bin"
+#define HW_Z_DIR "epoc32/data/z"
+
+#define SUFFIX_DLL "dll"
+#define SUFFIX_EXE "exe"
+#define SUFFIX_QTPLUGIN "qtplugin"
+
+static QString fixPathToEpocOS(const QString &src)
+{
+ QString ret = Option::fixPathToTargetOS(src);
+
+ bool pathHasDriveLetter = false;
+ if (ret.size() > 1)
+ pathHasDriveLetter = (ret.at(1) == QLatin1Char(':'));
+
+ return pathHasDriveLetter ? ret.replace('/', '\\') : QDir::toNativeSeparators(ret);
+}
+
+static bool isPlugin(const QFileInfo& info, const QString& devicePath)
+{
+ // Libraries are plugins if deployment path is something else than
+ // SYSBIN_DIR with or without drive letter
+ if (0 == info.suffix().compare(QLatin1String(SUFFIX_DLL), Qt::CaseInsensitive)
+ && (devicePath.size() < 8
+ || (0 != devicePath.compare(QLatin1String(SYSBIN_DIR), Qt::CaseInsensitive)
+ && 0 != devicePath.mid(1).compare(QLatin1String(":" SYSBIN_DIR), Qt::CaseInsensitive)
+ && 0 != devicePath.compare(qt_epocRoot() + QLatin1String(HW_Z_DIR SYSBIN_DIR))))) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static bool isBinary(const QFileInfo& info)
+{
+ if (0 == info.suffix().compare(QLatin1String(SUFFIX_DLL), Qt::CaseInsensitive) ||
+ 0 == info.suffix().compare(QLatin1String(SUFFIX_EXE), Qt::CaseInsensitive)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static void createPluginStub(const QFileInfo& info,
+ const QString& devicePath,
+ DeploymentList &deploymentList,
+ QStringList& generatedDirs,
+ QStringList& generatedFiles)
+{
+ QString pluginStubDir = Option::output_dir + QLatin1Char('/') + QLatin1String(PLUGIN_STUB_DIR);
+ QDir().mkpath(pluginStubDir);
+ if (!generatedDirs.contains(pluginStubDir))
+ generatedDirs << pluginStubDir;
+ // Plugin stubs must have different name from the actual plugins, because
+ // the toolchain for creating ROM images cannot handle non-binary .dll files properly.
+ QFile stubFile(pluginStubDir + QLatin1Char('/') + info.completeBaseName() + QLatin1Char('.') + QLatin1String(SUFFIX_QTPLUGIN));
+ if (stubFile.open(QIODevice::WriteOnly)) {
+ if (!generatedFiles.contains(stubFile.fileName()))
+ generatedFiles << stubFile.fileName();
+ QTextStream t(&stubFile);
+ // Add note to stub so that people will not wonder what it is.
+ // Creation date is added to make new stub to deploy always to
+ // force plugin cache miss when loading plugins.
+ t << "This file is a Qt plugin stub file. The real Qt plugin is located in " SYSBIN_DIR ". Created:" << QDateTime::currentDateTime().toString(Qt::ISODate) << "\n";
+ } else {
+ fprintf(stderr, "cannot deploy \"%s\" because of plugin stub file creation failed\n", info.fileName().toLatin1().constData());
+ }
+ QFileInfo stubInfo(stubFile);
+ deploymentList.append(CopyItem(Option::fixPathToLocalOS(stubInfo.absoluteFilePath()),
+ fixPathToEpocOS(devicePath + "/" + stubInfo.fileName())));
+}
+
+QString generate_uid(const QString& target)
+{
+ static QMap<QString, QString> targetToUid;
+
+ QString tmp = targetToUid[target];
+
+ if (!tmp.isEmpty()) {
+ return tmp;
+ }
+
+ quint32 hash = 5381;
+ int c;
+
+ for (int i = 0; i < target.size(); ++i) {
+ c = target.at(i).toAscii();
+ hash ^= c + ((c - i) << i % 20) + ((c + i) << (i + 5) % 20) + ((c - 2 * i) << (i + 10) % 20) + ((c + 2 * i) << (i + 15) % 20);
+ }
+
+ tmp.setNum(hash, 16);
+ for (int i = tmp.size(); i < 8; ++i)
+ tmp.prepend("0");
+
+ targetToUid[target] = tmp;
+
+ return tmp;
+}
+
+// UIDs starting with 0xE are test UIDs in symbian
+QString generate_test_uid(const QString& target)
+{
+ QString tmp = generate_uid(target);
+ tmp.replace(0, 1, "E");
+ tmp.prepend("0x");
+
+ return tmp;
+}
+
+
+void initProjectDeploySymbian(QMakeProject* project,
+ DeploymentList &deploymentList,
+ const QString &testPath,
+ bool deployBinaries,
+ bool epocBuild,
+ const QString &platform,
+ const QString &build,
+ QStringList& generatedDirs,
+ QStringList& generatedFiles)
+{
+ QString targetPath = testPath;
+ if (targetPath.endsWith("/") || targetPath.endsWith("\\"))
+ targetPath = targetPath.mid(0, targetPath.size() - 1);
+
+ bool targetPathHasDriveLetter = false;
+ if (targetPath.size() > 1) {
+ targetPathHasDriveLetter = targetPath.at(1) == QLatin1Char(':');
+ }
+
+ QString deploymentDrive;
+ if (0 == platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))) {
+ deploymentDrive = qt_epocRoot() + HW_Z_DIR;
+ } else {
+ deploymentDrive = targetPathHasDriveLetter ? targetPath.left(2) : QLatin1String("c:");
+ }
+
+ foreach(QString item, project->values("DEPLOYMENT")) {
+ QString devicePath = project->first(item + ".path");
+ QString devicePathWithoutDrive = devicePath;
+
+ bool devicePathHasDriveLetter = false;
+ if (devicePath.size() > 1) {
+ devicePathHasDriveLetter = devicePath.at(1) == QLatin1Char(':');
+ }
+
+ // Sometimes devicePath can contain disk but APP_RESOURCE_DIR does not,
+ // so remove the drive letter for comparison purposes.
+ if (devicePathHasDriveLetter)
+ {
+ devicePathWithoutDrive.remove(0,2);
+ }
+ if (!deployBinaries
+ && 0 != platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))
+ && !devicePathWithoutDrive.isEmpty()
+ && (0 == devicePathWithoutDrive.compare(project->values("APP_RESOURCE_DIR").join(""), Qt::CaseInsensitive)
+ || 0 == devicePathWithoutDrive.compare(project->values("REG_RESOURCE_IMPORT_DIR").join(""), Qt::CaseInsensitive))) {
+ // Do not deploy resources in emulator builds, as that seems to cause conflicts
+ // If there is ever a real need to deploy pre-built resources for emulator,
+ // BLD_INF_RULES.prj_exports can be used as a workaround.
+ continue;
+ }
+
+ if (devicePath.isEmpty() || devicePath == QLatin1String(".")) {
+ devicePath = targetPath;
+ }
+ // check if item.path is relative (! either / or \)
+ else if (!(devicePath.at(0) == QLatin1Char('/')
+ || devicePath.at(0) == QLatin1Char('\\')
+ || devicePathHasDriveLetter)) {
+ // Create output path
+ devicePath = Option::fixPathToLocalOS(QDir::cleanPath(targetPath + QLatin1Char('/') + devicePath));
+ } else {
+ if (0 == platform.compare(QLatin1String(EMULATOR_DEPLOYMENT_PLATFORM))) {
+ if (devicePathHasDriveLetter) {
+ if (devicePath.startsWith("!"))
+ devicePath = qt_epocRoot() + "epoc32/winscw/c" + devicePath.remove(0, 2);
+ else
+ devicePath = qt_epocRoot() + "epoc32/winscw/" + devicePath.remove(1, 1);
+ } else {
+ devicePath = qt_epocRoot() + "epoc32/winscw/c" + devicePath;
+ }
+ } else {
+ if (devicePathHasDriveLetter
+ && 0 == platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))) {
+ devicePath.remove(0,2);
+ }
+ if (0 == platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))
+ || (!devicePathHasDriveLetter && targetPathHasDriveLetter)) {
+ devicePath = deploymentDrive + devicePath;
+ }
+ }
+ }
+
+ devicePath.replace(QLatin1String("\\"), QLatin1String("/"));
+
+ if (!deployBinaries
+ && 0 == devicePath.right(8).compare(QLatin1String(SYSBIN_DIR), Qt::CaseInsensitive)
+ && 0 != platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))) {
+ // Skip deploying to SYSBIN_DIR for anything but binary deployments
+ // Note: Deploying pre-built binaries also follow this rule, so emulator builds
+ // will not get those deployed. Since there is no way to differentiate currently
+ // between pre-built binaries for emulator and HW anyway, this is not a major issue.
+ continue;
+ }
+
+ QStringList flags = project->values(item + ".flags");
+
+ // ### Qt 5: remove .sources, inconsistent with INSTALLS
+ foreach(QString source, project->values(item + ".sources") + project->values(item + ".files")) {
+ source = Option::fixPathToLocalOS(source);
+ QString nameFilter;
+ QFileInfo info(source);
+ QString searchPath;
+ bool dirSearch = false;
+
+ if (info.isDir()) {
+ nameFilter = QLatin1String("*");
+ searchPath = info.absoluteFilePath();
+ dirSearch = true;
+ } else {
+ if (info.exists() || source.indexOf('*') != -1) {
+ nameFilter = source.split(QDir::separator()).last();
+ searchPath = info.absolutePath();
+ } else {
+ // Entry was not found. That is ok if it is a binary, since those do not necessarily yet exist.
+ // Dlls need to be processed even when not deploying binaries for the stubs
+ if (isBinary(info)) {
+ if (deployBinaries) {
+ // Executables and libraries are deployed to \sys\bin
+ QFileInfo targetPath;
+ if (epocBuild)
+ targetPath.setFile(qt_epocRoot() + "epoc32/release/" + platform + "/" + build + "/");
+ else
+ targetPath.setFile(info.path() + QDir::separator());
+ if(devicePathHasDriveLetter) {
+ deploymentList.append(CopyItem(
+ Option::fixPathToLocalOS(targetPath.absolutePath() + "/" + info.fileName(),
+ false, true),
+ fixPathToEpocOS(devicePath.left(2) + QLatin1String(SYSBIN_DIR "/")
+ + info.fileName()),
+ flags));
+ } else {
+ deploymentList.append(CopyItem(
+ Option::fixPathToLocalOS(targetPath.absolutePath() + "/" + info.fileName(),
+ false, true),
+ fixPathToEpocOS(deploymentDrive + QLatin1String("/" SYSBIN_DIR "/")
+ + info.fileName()),
+ flags));
+ }
+ }
+ if (isPlugin(info, devicePath)) {
+ createPluginStub(info, devicePath, deploymentList, generatedDirs, generatedFiles);
+ continue;
+ }
+ } else {
+ // Generate deployment even if file doesn't exist, as this may be the case
+ // when generating .pkg files.
+ deploymentList.append(CopyItem(Option::fixPathToLocalOS(info.absoluteFilePath()),
+ fixPathToEpocOS(devicePath + "/" + info.fileName()),
+ flags));
+ continue;
+ }
+ }
+ }
+
+ int pathSize = info.absolutePath().size();
+ QDirIterator iterator(searchPath, QStringList() << nameFilter
+ , QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks
+ , dirSearch ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags);
+
+ while (iterator.hasNext()) {
+ iterator.next();
+ QFileInfo iteratorInfo(iterator.filePath());
+ QString absoluteItemPath = Option::fixPathToLocalOS(iteratorInfo.absolutePath());
+ int diffSize = absoluteItemPath.size() - pathSize;
+
+ if (!iteratorInfo.isDir()) {
+ if (isPlugin(iterator.fileInfo(), devicePath)) {
+ // This deploys pre-built plugins. Other pre-built binaries will deploy normally,
+ // as they have SYSBIN_DIR target path.
+ if (deployBinaries
+ || (0 == platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM)))) {
+ if (devicePathHasDriveLetter) {
+ deploymentList.append(CopyItem(
+ Option::fixPathToLocalOS(absoluteItemPath + "/" + iterator.fileName()),
+ fixPathToEpocOS(devicePath.left(2) + QLatin1String(SYSBIN_DIR "/")
+ + iterator.fileName()),
+ flags));
+ } else {
+ deploymentList.append(CopyItem(
+ Option::fixPathToLocalOS(absoluteItemPath + "/" + iterator.fileName()),
+ fixPathToEpocOS(deploymentDrive + QLatin1String("/" SYSBIN_DIR "/")
+ + iterator.fileName()),
+ flags));
+ }
+ }
+ createPluginStub(info, devicePath + "/" + absoluteItemPath.right(diffSize),
+ deploymentList, generatedDirs, generatedFiles);
+ continue;
+ } else {
+ deploymentList.append(CopyItem(
+ Option::fixPathToLocalOS(absoluteItemPath + "/" + iterator.fileName()),
+ fixPathToEpocOS(devicePath + "/" + absoluteItemPath.right(diffSize)
+ + "/" + iterator.fileName()),
+ flags));
+ }
+ }
+ }
+ }
+ }
+
+ // Remove deployments that do not actually do anything
+ if (0 == platform.compare(QLatin1String(EMULATOR_DEPLOYMENT_PLATFORM))
+ || 0 == platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))) {
+ QMutableListIterator<CopyItem> i(deploymentList);
+ while(i.hasNext()) {
+ CopyItem &item = i.next();
+ QFileInfo fromItem(item.from);
+ QFileInfo toItem(item.to);
+#if defined(Q_OS_WIN)
+ if (0 == fromItem.absoluteFilePath().compare(toItem.absoluteFilePath(), Qt::CaseInsensitive))
+#else
+ if (0 == fromItem.absoluteFilePath().compare(toItem.absoluteFilePath()))
+#endif
+ i.remove();
+ }
+ }
+}
diff --git a/qmake/generators/symbian/initprojectdeploy_symbian.h b/qmake/generators/symbian/initprojectdeploy_symbian.h
new file mode 100644
index 0000000000..539f4c4248
--- /dev/null
+++ b/qmake/generators/symbian/initprojectdeploy_symbian.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INITPROJECTDEPLOYSYMBIAN_H
+#define INITPROJECTDEPLOYSYMBIAN_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+#include <option.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <stdlib.h>
+
+#define PLUGIN_STUB_DIR "qmakepluginstubs"
+#define ROM_DEPLOYMENT_PLATFORM "rom"
+#define EMULATOR_DEPLOYMENT_PLATFORM "emulator"
+
+struct CopyItem
+{
+ CopyItem(const QString& f, const QString& t)
+ : from(f) , to(t) { }
+ CopyItem(const QString& f, const QString& t, const QStringList& l)
+ : from(f) , to(t), flags(l) { }
+ QString from;
+ QString to;
+ QStringList flags;
+};
+typedef QList<CopyItem> DeploymentList;
+
+extern QString generate_uid(const QString& target);
+extern QString generate_test_uid(const QString& target);
+
+extern void initProjectDeploySymbian(QMakeProject* project,
+ DeploymentList &deploymentList,
+ const QString &testPath,
+ bool deployBinaries,
+ bool epocBuild,
+ const QString &platform,
+ const QString &build,
+ QStringList& generatedDirs,
+ QStringList& generatedFiles);
+
+#endif // INITPROJECTDEPLOYSYMBIAN_H
diff --git a/qmake/generators/symbian/symbian_makefile.h b/qmake/generators/symbian/symbian_makefile.h
new file mode 100644
index 0000000000..c49845aeb1
--- /dev/null
+++ b/qmake/generators/symbian/symbian_makefile.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYMBIAN_MAKEFILE_H
+#define SYMBIAN_MAKEFILE_H
+
+#include "symbiancommon.h"
+
+// This allows us to reuse the code for both win32 and unix makefile generators.
+template <class T>
+class SymbianMakefileTemplate : public T, public SymbianCommonGenerator
+{
+public:
+ SymbianMakefileTemplate() : SymbianCommonGenerator(this) {}
+
+ void init()
+ {
+ T::init();
+ SymbianCommonGenerator::init();
+ }
+
+ bool writeMakefile(QTextStream &t)
+ {
+ QString numberOfIcons;
+ QString iconFile;
+ QMap<QString, QStringList> userRssRules;
+ readRssRules(numberOfIcons, iconFile, userRssRules);
+
+ // Generate pkg files if there are any actual files to deploy
+ bool generatePkg = false;
+
+ if (targetType == TypeExe) {
+ generatePkg = true;
+ } else {
+ const QStringList deployments = this->project->values("DEPLOYMENT");
+ for (int i = 0; i < deployments.count(); ++i) {
+ // ### Qt 5: remove .sources, inconsistent with INSTALLS
+ if (!this->project->values(deployments.at(i) + ".sources").isEmpty() ||
+ !this->project->values(deployments.at(i) + ".files").isEmpty()) {
+ generatePkg = true;
+ break;
+ }
+ }
+ }
+
+ SymbianLocalizationList symbianLocalizationList;
+ parseTsFiles(&symbianLocalizationList);
+
+ if (generatePkg) {
+ generatePkgFile(iconFile, false, symbianLocalizationList);
+ }
+
+ if (targetType == TypeExe) {
+ if (!this->project->values("CONFIG").contains("no_icon", Qt::CaseInsensitive)) {
+ writeRegRssFile(userRssRules);
+ writeRssFile(numberOfIcons, iconFile);
+ writeLocFile(symbianLocalizationList);
+ }
+ }
+
+ writeCustomDefFile();
+
+ return T::writeMakefile(t);
+ }
+};
+
+#endif // SYMBIAN_MAKEFILE_H
diff --git a/qmake/generators/symbian/symbiancommon.cpp b/qmake/generators/symbian/symbiancommon.cpp
new file mode 100644
index 0000000000..32b465b4bf
--- /dev/null
+++ b/qmake/generators/symbian/symbiancommon.cpp
@@ -0,0 +1,1117 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "symbiancommon.h"
+#include <qdebug.h>
+#include <qxmlstream.h>
+
+// Included from tools/shared
+#include <symbian/epocroot_p.h>
+
+#define RESOURCE_DIRECTORY_RESOURCE "\\\\resource\\\\apps\\\\"
+
+#define RSS_RULES "RSS_RULES"
+#define RSS_RULES_BASE "RSS_RULES."
+#define RSS_TAG_NBROFICONS "number_of_icons"
+#define RSS_TAG_ICONFILE "icon_file"
+#define RSS_TAG_HEADER "header"
+#define RSS_TAG_SERVICE_LIST "service_list"
+#define RSS_TAG_FILE_OWNERSHIP_LIST "file_ownership_list"
+#define RSS_TAG_DATATYPE_LIST "datatype_list"
+#define RSS_TAG_FOOTER "footer"
+#define RSS_TAG_DEFAULT "default_rules" // Same as just giving rules without tag
+
+#define PLUGIN_COMMON_DEF_FILE_ACTUAL "plugin_commonu.def"
+
+#define MANUFACTURER_NOTE_FILE "manufacturer_note.txt"
+#define DEFAULT_MANUFACTURER_NOTE \
+ "The package is not supported for devices from this manufacturer. Please try the selfsigned " \
+ "version of the package instead."
+
+SymbianCommonGenerator::SymbianCommonGenerator(MakefileGenerator *generator)
+ : generator(generator)
+{
+}
+
+void SymbianCommonGenerator::init()
+{
+ QMakeProject *project = generator->project;
+ fixedTarget = project->first("QMAKE_ORIG_TARGET");
+ if (fixedTarget.isEmpty())
+ fixedTarget = project->first("TARGET");
+ fixedTarget = generator->unescapeFilePath(fixedTarget);
+ fixedTarget = removePathSeparators(fixedTarget);
+ removeSpecialCharacters(fixedTarget);
+
+ // This should not be empty since the mkspecs are supposed to set it if missing.
+ uid3 = project->first("TARGET.UID3").trimmed();
+
+ if ((project->values("TEMPLATE")).contains("app"))
+ targetType = TypeExe;
+ else if ((project->values("TEMPLATE")).contains("lib")) {
+ // Check CONFIG to see if we are to build staticlib or dll
+ if (project->isActiveConfig("staticlib") || project->isActiveConfig("static"))
+ targetType = TypeLib;
+ else if (project->isActiveConfig("plugin"))
+ targetType = TypePlugin;
+ else
+ targetType = TypeDll;
+ } else {
+ targetType = TypeSubdirs;
+ }
+
+ // UID is valid as either hex or decimal, so just convert it to number and back to hex
+ // to get proper string for private dir
+ bool conversionOk = false;
+ uint uidNum = uid3.toUInt(&conversionOk, 0);
+
+ if (!conversionOk) {
+ fprintf(stderr, "Error: Invalid UID \"%s\".\n", uid3.toUtf8().constData());
+ } else {
+ privateDirUid.setNum(uidNum, 16);
+ while (privateDirUid.length() < 8)
+ privateDirUid.insert(0, QLatin1Char('0'));
+ }
+}
+
+bool SymbianCommonGenerator::containsStartWithItem(const QChar &c, const QStringList& src)
+{
+ bool result = false;
+ foreach(QString str, src) {
+ if (str.startsWith(c)) {
+ result = true;
+ break;
+ }
+ }
+ return result;
+}
+
+void SymbianCommonGenerator::removeSpecialCharacters(QString& str)
+{
+ // When modifying this method check also symbianRemoveSpecialCharacters in symbian.conf
+ QString underscore = QLatin1String("_");
+ str.replace(QLatin1String("/"), underscore);
+ str.replace(QLatin1String("\\"), underscore);
+ str.replace(QLatin1String(" "), underscore);
+ str.replace(QLatin1String(":"), underscore);
+}
+
+QString romPath(const QString& path)
+{
+ if(path.length() > 2 && path[1] == ':')
+ return QLatin1String("z:") + path.mid(2);
+ return QLatin1String("z:") + path;
+}
+
+void SymbianCommonGenerator::generatePkgFile(const QString &iconFile,
+ bool epocBuild,
+ const SymbianLocalizationList &symbianLocalizationList)
+{
+ QMakeProject *project = generator->project;
+ QString pkgFilename = Option::output_dir + QLatin1Char('/') +
+ QString("%1_template.pkg").arg(fixedTarget);
+
+ QFile pkgFile(pkgFilename);
+ if (!pkgFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ PRINT_FILE_CREATE_ERROR(pkgFilename);
+ return;
+ }
+
+ QString stubPkgFileName = Option::output_dir + QLatin1Char('/') +
+ QString("%1_stub.pkg").arg(fixedTarget);
+
+ QFile stubPkgFile(stubPkgFileName);
+ if (!stubPkgFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ PRINT_FILE_CREATE_ERROR(stubPkgFileName);
+ return;
+ }
+
+ generatedFiles << pkgFile.fileName();
+ QTextStream t(&pkgFile);
+ generatedFiles << stubPkgFile.fileName();
+ QTextStream ts(&stubPkgFile);
+
+ QString installerSisHeader = project->values("DEPLOYMENT.installer_header").join("\n");
+ if (installerSisHeader.isEmpty()) {
+ // Use correct protected UID for publishing if application UID is in protected range,
+ // otherwise use self-signable test UID.
+ QRegExp protUidMatcher("0[xX][0-7].*");
+ if (protUidMatcher.exactMatch(uid3))
+ installerSisHeader = QLatin1String("0x2002CCCF");
+ else
+ installerSisHeader = QLatin1String("0xA000D7CE"); // Use default self-signable UID
+ }
+
+ QString wrapperStreamBuffer;
+ QTextStream tw(&wrapperStreamBuffer);
+
+ QString dateStr = QDateTime::currentDateTime().toString(Qt::ISODate);
+
+ // Header info
+ QString wrapperPkgFilename = Option::output_dir + QLatin1Char('/') + QString("%1_installer.%2")
+ .arg(fixedTarget).arg("pkg");
+
+ QString headerComment = "; %1 generated by qmake at %2\n"
+ "; This file is generated by qmake and should not be modified by the user\n"
+ ";\n\n";
+ t << headerComment.arg(pkgFilename).arg(dateStr);
+ tw << headerComment.arg(wrapperPkgFilename).arg(dateStr);
+ ts << headerComment.arg(stubPkgFileName).arg(dateStr);
+
+ QStringList commonRawPreRules;
+ QStringList mainRawPreRules;
+ QStringList instRawPreRules;
+ QStringList stubRawPreRules;
+
+ // Though there can't be more than one language or header line, use stringlists
+ // in case user wants comments to go with the rules.
+ // Note that it makes no sense to have file specific language or header rules,
+ // except what is provided for installer header via "DEPLOYMENT.installer_header" variable,
+ // because stub and main headers should always match. Vendor rules are similarly limited to
+ // make code cleaner as it is unlikely anyone will want different vendor in different files.
+ QStringList languageRules;
+ QStringList headerRules;
+ QStringList vendorRules;
+
+ QStringList commonRawPostRules;
+ QStringList mainRawPostRules;
+ QStringList instRawPostRules;
+ QStringList stubRawPostRules;
+
+ QStringList failList; // Used for detecting incorrect usage
+
+ QString emptySuffix;
+ QString mainSuffix(".main");
+ QString instSuffix(".installer");
+ QString stubSuffix(".stub");
+
+ foreach(QString item, project->values("DEPLOYMENT")) {
+ parsePreRules(item, emptySuffix, &commonRawPreRules, &languageRules, &headerRules, &vendorRules);
+ parsePreRules(item, mainSuffix, &mainRawPreRules, &failList, &failList, &failList);
+ parsePreRules(item, instSuffix, &instRawPreRules, &failList, &failList, &failList);
+ parsePreRules(item, stubSuffix, &stubRawPreRules, &failList, &failList, &failList);
+
+ parsePostRules(item, emptySuffix, &commonRawPostRules);
+ parsePostRules(item, mainSuffix, &mainRawPostRules);
+ parsePostRules(item, instSuffix, &instRawPostRules);
+ parsePostRules(item, stubSuffix, &stubRawPostRules);
+ }
+
+ if (!failList.isEmpty()) {
+ fprintf(stderr, "Warning: Custom language, header, or vendor definitions are not "
+ "supported by file specific pkg_prerules.* variables.\n"
+ "Use plain pkg_prerules and/or DEPLOYMENT.installer_header for customizing "
+ "these items.\n");
+ }
+
+ foreach(QString item, commonRawPreRules) {
+ if (item.startsWith("(")) {
+ // Only regular pkg file should have package dependencies
+ mainRawPreRules << item;
+ } else if (item.startsWith("[")) {
+ // stub pkg file should not have platform dependencies
+ mainRawPreRules << item;
+ instRawPreRules << item;
+ } else {
+ mainRawPreRules << item;
+ instRawPreRules << item;
+ stubRawPreRules << item;
+ }
+ }
+
+ // Currently common postrules only go to main
+ mainRawPostRules << commonRawPostRules;
+
+ // Apply some defaults if specific data does not exist in PKG pre-rules
+ if (languageRules.isEmpty()) {
+ if (symbianLocalizationList.isEmpty()) {
+ languageRules << "; Language\n&EN\n\n";
+ } else {
+ QStringList langCodes;
+ SymbianLocalizationListIterator iter(symbianLocalizationList);
+ while (iter.hasNext()) {
+ const SymbianLocalization &loc = iter.next();
+ langCodes << loc.symbianLanguageCode;
+ }
+ languageRules << QString("; Languages\n&%1\n\n").arg(langCodes.join(","));
+ }
+ } else if (headerRules.isEmpty()) {
+ // In case user defines langs, he must take care also about SIS header
+ fprintf(stderr, "Warning: If language is defined with DEPLOYMENT pkg_prerules, also the SIS header must be defined\n");
+ }
+
+ t << languageRules.join("\n") << endl;
+ tw << languageRules.join("\n") << endl;
+ ts << languageRules.join("\n") << endl;
+
+ // Determine application version. If version has missing component values,
+ // those will default to zero.
+ // If VERSION is missing altogether or is invalid, use "1,0,0"
+ QStringList verNumList = project->first("VERSION").split('.');
+ uint major = 0;
+ uint minor = 0;
+ uint patch = 0;
+ bool success = false;
+
+ if (verNumList.size() > 0) {
+ major = verNumList[0].toUInt(&success);
+ if (success && verNumList.size() > 1) {
+ minor = verNumList[1].toUInt(&success);
+ if (success && verNumList.size() > 2) {
+ patch = verNumList[2].toUInt(&success);
+ }
+ }
+ }
+
+ QString applicationVersion("1,0,0");
+ if (success)
+ applicationVersion = QString("%1,%2,%3").arg(major).arg(minor).arg(patch);
+
+ // Append package build version number if it is set
+ QString pkgBuildVersion = project->first("DEPLOYMENT.pkg_build_version");
+ if (!pkgBuildVersion.isEmpty()) {
+ success = false;
+ uint build = pkgBuildVersion.toUInt(&success);
+ if (success && build < 100) {
+ if (pkgBuildVersion.size() == 1)
+ pkgBuildVersion.prepend(QLatin1Char('0'));
+ applicationVersion.append(pkgBuildVersion);
+ } else {
+ fprintf(stderr, "Warning: Invalid DEPLOYMENT.pkg_build_version (%s), must be a number between 0 - 99\n", qPrintable(pkgBuildVersion));
+ }
+ }
+
+ // Package header
+ QString sisHeader = "; SIS header: name, uid, version\n#{\"%1\"},(%2),%3\n\n";
+
+ QString defaultVisualTarget = project->values("DEPLOYMENT.display_name").join(" ");
+ if (defaultVisualTarget.isEmpty())
+ defaultVisualTarget = generator->escapeFilePath(project->first("TARGET"));
+ defaultVisualTarget = removePathSeparators(defaultVisualTarget);
+
+ QString visualTarget = generatePkgNameForHeader(symbianLocalizationList, defaultVisualTarget, false);
+ QString wrapperTarget = generatePkgNameForHeader(symbianLocalizationList, defaultVisualTarget, true);
+
+ if (installerSisHeader.startsWith("0x", Qt::CaseInsensitive)) {
+ tw << sisHeader.arg(wrapperTarget).arg(installerSisHeader).arg(applicationVersion);
+ } else {
+ tw << installerSisHeader << endl;
+ }
+
+ if (headerRules.isEmpty()) {
+ t << sisHeader.arg(visualTarget).arg(uid3).arg(applicationVersion);
+ ts << sisHeader.arg(visualTarget).arg(uid3).arg(applicationVersion);
+ }
+ else {
+ t << headerRules.join("\n") << endl;
+ ts << headerRules.join("\n") << endl;
+ }
+
+ // Vendor name
+ if (!containsStartWithItem('%', vendorRules)) {
+ QString vendorStr = QLatin1String("\"Vendor\",");
+ QString locVendors = vendorStr;
+ for (int i = 1; i < symbianLocalizationList.size(); i++) {
+ locVendors.append(vendorStr);
+ }
+ locVendors.chop(1);
+ vendorRules << QString("; Default localized vendor name\n%{%1}\n\n").arg(locVendors);
+ }
+ if (!containsStartWithItem(':', vendorRules)) {
+ vendorRules << "; Default unique vendor name\n:\"Vendor\"\n\n";
+ }
+
+ t << vendorRules.join("\n") << endl;
+ tw << vendorRules.join("\n") << endl;
+ ts << vendorRules.join("\n") << endl;
+
+ // PKG pre-rules - these are added before actual file installations i.e. SIS package body
+ QString comment = "\n; Manual PKG pre-rules from PRO files\n";
+
+ if (mainRawPreRules.size()) {
+ t << comment;
+ t << mainRawPreRules.join("\n") << endl;
+ }
+ if (instRawPreRules.size()) {
+ tw << comment;
+ tw << instRawPreRules.join("\n") << endl;
+ }
+ if (stubRawPreRules.size()) {
+ ts << comment;
+ ts << stubRawPreRules.join("\n") << endl;
+ }
+
+ t << endl;
+ tw << endl;
+ ts << endl;
+
+ // Begin Manufacturer block
+ if (!project->values("DEPLOYMENT.manufacturers").isEmpty()) {
+ QString manufacturerStr("IF ");
+ foreach(QString manufacturer, project->values("DEPLOYMENT.manufacturers")) {
+ manufacturerStr.append(QString("(MANUFACTURER)=(%1) OR \n ").arg(manufacturer));
+ }
+ // Remove the final OR
+ manufacturerStr.chop(8);
+ t << manufacturerStr << endl;
+ }
+
+ if (symbianLocalizationList.size()) {
+ // Add localized resources to DEPLOYMENT if default resource deployment is done
+ addLocalizedResourcesToDeployment("default_resource_deployment.files", symbianLocalizationList);
+ addLocalizedResourcesToDeployment("default_reg_deployment.files", symbianLocalizationList);
+ }
+
+ // deploy files specified by DEPLOYMENT variable
+ QString remoteTestPath;
+ QString zDir;
+ remoteTestPath = QString("!:\\private\\%1").arg(privateDirUid);
+ if (epocBuild)
+ zDir = qt_epocRoot() + QLatin1String("epoc32/data/z");
+
+ DeploymentList depList;
+ initProjectDeploySymbian(project, depList, remoteTestPath, true, epocBuild, "$(PLATFORM)", "$(TARGET)", generatedDirs, generatedFiles);
+ if (depList.size())
+ t << "; DEPLOYMENT" << endl;
+ for (int i = 0; i < depList.size(); ++i) {
+ QString from = depList.at(i).from;
+ QString to = depList.at(i).to;
+ QString flags;
+ bool showOnlyFile = false;
+ foreach(QString flag, depList.at(i).flags) {
+ if (flag == QLatin1String("FT")
+ || flag == QLatin1String("FILETEXT")) {
+ showOnlyFile = true;
+ }
+ flags.append(QLatin1Char(',')).append(flag);
+ }
+
+ if (epocBuild) {
+ // Deploy anything not already deployed from under epoc32 instead from under
+ // \epoc32\data\z\ to enable using pkg file without rebuilding
+ // the project, which can be useful for some binary only distributions.
+ if (!from.contains(QLatin1String("epoc32"), Qt::CaseInsensitive)) {
+ from = to;
+ if (from.size() > 1 && from.at(1) == QLatin1Char(':'))
+ from = from.mid(2);
+ from.prepend(zDir);
+ }
+ }
+
+ // Files with "FILETEXT"/"FT" flag are meant for showing only at installation time
+ // and therefore do not belong to the stub package and will not install the file into phone.
+ if (showOnlyFile)
+ to.clear();
+ else
+ ts << QString("\"\" - \"%1\"").arg(romPath(to)) << endl;
+
+ t << QString("\"%1\" - \"%2\"%3").arg(from.replace('\\','/')).arg(to).arg(flags) << endl;
+
+ }
+ t << endl;
+ ts << endl;
+
+ // PKG post-rules - these are added after actual file installations i.e. SIS package body
+ comment = "; Manual PKG post-rules from PRO files\n";
+
+ if (mainRawPostRules.size()) {
+ t << comment;
+ t << mainRawPostRules.join("\n") << endl;
+ }
+ if (instRawPostRules.size()) {
+ tw << comment;
+ tw << instRawPostRules.join("\n") << endl;
+ }
+ if (stubRawPostRules.size()) {
+ ts << comment;
+ ts << stubRawPostRules.join("\n") << endl;
+ }
+
+ // Close Manufacturer block
+ if (!project->values("DEPLOYMENT.manufacturers").isEmpty()) {
+ QString manufacturerFailNoteFile;
+ if (project->values("DEPLOYMENT.manufacturers.fail_note").isEmpty()) {
+ manufacturerFailNoteFile = QString("%1_" MANUFACTURER_NOTE_FILE).arg(uid3);
+ QFile ft(manufacturerFailNoteFile);
+ if (ft.open(QIODevice::WriteOnly)) {
+ generatedFiles << ft.fileName();
+ QTextStream t2(&ft);
+
+ t2 << QString(DEFAULT_MANUFACTURER_NOTE) << endl;
+ } else {
+ PRINT_FILE_CREATE_ERROR(manufacturerFailNoteFile)
+ }
+ } else {
+ manufacturerFailNoteFile = project->values("DEPLOYMENT.manufacturers.fail_note").join("");
+ }
+
+ t << "ELSEIF NOT(0) ; MANUFACTURER" << endl
+ << "\"" << generator->fileInfo(manufacturerFailNoteFile).absoluteFilePath() << "\""
+ << " - \"\", FILETEXT, TEXTEXIT" << endl
+ << "ENDIF ; MANUFACTURER" << endl;
+ }
+
+ // Write wrapper pkg
+ if (!installerSisHeader.isEmpty()) {
+ QFile wrapperPkgFile(wrapperPkgFilename);
+ if (!wrapperPkgFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ PRINT_FILE_CREATE_ERROR(wrapperPkgFilename);
+ return;
+ }
+
+ generatedFiles << wrapperPkgFile.fileName();
+ QTextStream twf(&wrapperPkgFile);
+
+ twf << wrapperStreamBuffer << endl;
+
+ // Wrapped files deployment
+ QString currentPath = qmake_getpwd();
+ QString sisName = QString("%1.sis").arg(fixedTarget);
+ twf << "\"" << currentPath << "/" << sisName << "\" - \"!:\\private\\2002CCCE\\import\\" << sisName << "\"" << endl;
+
+ QString bootStrapPath = QLibraryInfo::location(QLibraryInfo::PrefixPath);
+ bootStrapPath.append("/smartinstaller.sis");
+ QFileInfo fi(generator->fileInfo(bootStrapPath));
+ twf << "@\"" << fi.absoluteFilePath() << "\",(0x2002CCCD)" << endl;
+ }
+}
+
+QString SymbianCommonGenerator::removePathSeparators(QString &file)
+{
+ QString ret = file;
+
+ if (QDir::separator().unicode() != '/')
+ ret.replace(QDir::separator(), QLatin1Char('/'));
+
+ if (ret.indexOf(QLatin1Char('/')) >= 0)
+ ret.remove(0, ret.lastIndexOf(QLatin1Char('/')) + 1);
+
+ return ret;
+}
+
+void SymbianCommonGenerator::writeRegRssFile(QMap<QString, QStringList> &userItems)
+{
+ QString filename(fixedTarget);
+ filename.append("_reg.rss");
+ if (!Option::output_dir.isEmpty())
+ filename = Option::output_dir + '/' + filename;
+ QFile ft(filename);
+ if (ft.open(QIODevice::WriteOnly)) {
+ generatedFiles << ft.fileName();
+ QTextStream t(&ft);
+ t << "// ============================================================================" << endl;
+ t << "// * Generated by qmake (" << qmake_version() << ") (Qt " QT_VERSION_STR ") on: ";
+ t << QDateTime::currentDateTime().toString(Qt::ISODate) << endl;
+ t << "// * This file is generated by qmake and should not be modified by the" << endl;
+ t << "// * user." << endl;
+ t << "// ============================================================================" << endl;
+ t << endl;
+ t << "#include <" << fixedTarget << ".rsg>" << endl;
+ t << "#include <appinfo.rh>" << endl;
+ foreach(QString item, userItems[RSS_TAG_HEADER])
+ t << item << endl;
+ t << endl;
+ t << "UID2 KUidAppRegistrationResourceFile" << endl;
+ t << "UID3 " << uid3 << endl << endl;
+ t << "RESOURCE APP_REGISTRATION_INFO" << endl;
+ t << "\t{" << endl;
+ t << "\tapp_file=\"" << fixedTarget << "\";" << endl;
+ t << "\tlocalisable_resource_file=\"" RESOURCE_DIRECTORY_RESOURCE << fixedTarget << "\";" << endl;
+
+ writeRegRssList(t, userItems[RSS_TAG_SERVICE_LIST],
+ QLatin1String(RSS_TAG_SERVICE_LIST),
+ QLatin1String("SERVICE_INFO"));
+ writeRegRssList(t, userItems[RSS_TAG_FILE_OWNERSHIP_LIST],
+ QLatin1String(RSS_TAG_FILE_OWNERSHIP_LIST),
+ QLatin1String("FILE_OWNERSHIP_INFO"));
+ writeRegRssList(t, userItems[RSS_TAG_DATATYPE_LIST],
+ QLatin1String(RSS_TAG_DATATYPE_LIST),
+ QLatin1String("DATATYPE"));
+ t << endl;
+
+ foreach(QString item, userItems[RSS_TAG_DEFAULT])
+ t << "\t" << item.replace("\n","\n\t") << endl;
+ t << "\t}" << endl;
+
+ foreach(QString item, userItems[RSS_TAG_FOOTER])
+ t << item << endl;
+ } else {
+ PRINT_FILE_CREATE_ERROR(filename)
+ }
+}
+
+void SymbianCommonGenerator::writeRegRssList(QTextStream &t,
+ QStringList &userList,
+ const QString &listTag,
+ const QString &listItem)
+{
+ int itemCount = userList.count();
+ if (itemCount) {
+ t << "\t" << listTag << " ="<< endl;
+ t << "\t\t{" << endl;
+ foreach(QString item, userList) {
+ t << "\t\t" << listItem << endl;
+ t << "\t\t\t{" << endl;
+ t << "\t\t\t" << item.replace("\n","\n\t\t\t") << endl;
+ t << "\t\t\t}";
+ if (--itemCount)
+ t << ",";
+ t << endl;
+ }
+ t << "\t\t}; "<< endl;
+ }
+}
+
+void SymbianCommonGenerator::writeRssFile(QString &numberOfIcons, QString &iconFile)
+{
+ QString filename(fixedTarget);
+ if (!Option::output_dir.isEmpty())
+ filename = Option::output_dir + '/' + filename;
+ filename.append(".rss");
+ QFile ft(filename);
+ if (ft.open(QIODevice::WriteOnly)) {
+ generatedFiles << ft.fileName();
+ QTextStream t(&ft);
+ t << "// ============================================================================" << endl;
+ t << "// * Generated by qmake (" << qmake_version() << ") (Qt " QT_VERSION_STR ") on: ";
+ t << QDateTime::currentDateTime().toString(Qt::ISODate) << endl;
+ t << "// * This file is generated by qmake and should not be modified by the" << endl;
+ t << "// * user." << endl;
+ t << "// ============================================================================" << endl;
+ t << endl;
+ t << "CHARACTER_SET UTF8" << endl;
+ t << "#include <appinfo.rh>" << endl;
+ t << "#include \"" << fixedTarget << ".loc\"" << endl;
+ t << endl;
+ t << "RESOURCE LOCALISABLE_APP_INFO r_localisable_app_info" << endl;
+ t << "\t{" << endl;
+ t << "\tshort_caption = STRING_r_short_caption;" << endl;
+ t << "\tcaption_and_icon =" << endl;
+ t << "\tCAPTION_AND_ICON_INFO" << endl;
+ t << "\t\t{" << endl;
+ t << "\t\tcaption = STRING_r_caption;" << endl;
+
+ QString rssIconFile = iconFile;
+ rssIconFile = rssIconFile.replace("/", "\\\\");
+
+ if (numberOfIcons.isEmpty() || rssIconFile.isEmpty()) {
+ // There can be maximum one item in this tag, validated when parsed
+ t << "\t\tnumber_of_icons = 0;" << endl;
+ t << "\t\ticon_file = \"\";" << endl;
+ } else {
+ // There can be maximum one item in this tag, validated when parsed
+ t << "\t\tnumber_of_icons = " << numberOfIcons << ";" << endl;
+ t << "\t\ticon_file = \"" << rssIconFile << "\";" << endl;
+ }
+ t << "\t\t};" << endl;
+ t << "\t}" << endl;
+ t << endl;
+ } else {
+ PRINT_FILE_CREATE_ERROR(filename);
+ }
+}
+
+void SymbianCommonGenerator::writeLocFile(const SymbianLocalizationList &symbianLocalizationList)
+{
+ QString filename = generateLocFileName();
+ QFile ft(filename);
+ if (ft.open(QIODevice::WriteOnly)) {
+ generatedFiles << ft.fileName();
+ QTextStream t(&ft);
+
+ QString displayName = generator->project->values("DEPLOYMENT.display_name").join(" ");
+ if (displayName.isEmpty())
+ displayName = generator->escapeFilePath(generator->project->first("TARGET"));
+
+ t << "// ============================================================================" << endl;
+ t << "// * Generated by qmake (" << qmake_version() << ") (Qt " QT_VERSION_STR ") on: ";
+ t << QDateTime::currentDateTime().toString(Qt::ISODate) << endl;
+ t << "// * This file is generated by qmake and should not be modified by the" << endl;
+ t << "// * user." << endl;
+ t << "// ============================================================================" << endl;
+ t << endl;
+ t << "#ifdef LANGUAGE_SC" << endl;
+ t << "#define STRING_r_short_caption \"" << displayName << "\"" << endl;
+ t << "#define STRING_r_caption \"" << displayName << "\"" << endl;
+
+ SymbianLocalizationListIterator iter(symbianLocalizationList);
+ while (iter.hasNext()) {
+ const SymbianLocalization &loc = iter.next();
+ QString shortCaption = loc.shortCaption;
+ QString longCaption = loc.longCaption;
+ if (shortCaption.isEmpty())
+ shortCaption = displayName;
+ if (longCaption.isEmpty())
+ longCaption = displayName;
+
+ t << "#elif defined LANGUAGE_" << loc.symbianLanguageCode << endl;
+ t << "#define STRING_r_short_caption \"" << shortCaption << "\"" << endl;
+ t << "#define STRING_r_caption \"" << longCaption << "\"" << endl;
+ }
+
+ t << "#else" << endl;
+ t << "#define STRING_r_short_caption \"" << displayName << "\"" << endl;
+ t << "#define STRING_r_caption \"" << displayName << "\"" << endl;
+ t << "#endif" << endl;
+ } else {
+ PRINT_FILE_CREATE_ERROR(filename);
+ }
+}
+
+void SymbianCommonGenerator::readRssRules(QString &numberOfIcons,
+ QString &iconFile, QMap<QString,
+ QStringList> &userRssRules)
+{
+ QMakeProject *project = generator->project;
+ for (QMap<QString, QStringList>::iterator it = project->variables().begin(); it != project->variables().end(); ++it) {
+ if (it.key().startsWith(RSS_RULES_BASE)) {
+ QString newKey = it.key().mid(sizeof(RSS_RULES_BASE) - 1);
+ if (newKey.isEmpty()) {
+ fprintf(stderr, "Warning: Empty RSS_RULES_BASE key encountered\n");
+ continue;
+ }
+ QStringList newValues;
+ QStringList values = it.value();
+ foreach(QString item, values) {
+ // If there is no stringlist defined for a rule, use rule value directly
+ // This is convenience for defining single line statements
+ if (project->values(item).isEmpty()) {
+ newValues << item;
+ } else {
+ QStringList itemList;
+ foreach(QString itemRow, project->values(item)) {
+ itemList << itemRow;
+ }
+ newValues << itemList.join("\n");
+ }
+ }
+ // Verify that there is exactly one value in RSS_TAG_NBROFICONS
+ if (newKey == RSS_TAG_NBROFICONS) {
+ if (newValues.count() == 1) {
+ numberOfIcons = newValues[0];
+ } else {
+ fprintf(stderr, "Warning: There must be exactly one value in '%s%s'\n",
+ RSS_RULES_BASE, RSS_TAG_NBROFICONS);
+ continue;
+ }
+ // Verify that there is exactly one value in RSS_TAG_ICONFILE
+ } else if (newKey == RSS_TAG_ICONFILE) {
+ if (newValues.count() == 1) {
+ iconFile = newValues[0];
+ } else {
+ fprintf(stderr, "Warning: There must be exactly one value in '%s%s'\n",
+ RSS_RULES_BASE, RSS_TAG_ICONFILE);
+ continue;
+ }
+ } else if (newKey == RSS_TAG_HEADER
+ || newKey == RSS_TAG_SERVICE_LIST
+ || newKey == RSS_TAG_FILE_OWNERSHIP_LIST
+ || newKey == RSS_TAG_DATATYPE_LIST
+ || newKey == RSS_TAG_FOOTER
+ || newKey == RSS_TAG_DEFAULT) {
+ userRssRules[newKey] = newValues;
+ continue;
+ } else {
+ fprintf(stderr, "Warning: Unsupported key:'%s%s'\n",
+ RSS_RULES_BASE, newKey.toLatin1().constData());
+ continue;
+ }
+ }
+ }
+
+ QStringList newValues;
+ foreach(QString item, project->values(RSS_RULES)) {
+ // If there is no stringlist defined for a rule, use rule value directly
+ // This is convenience for defining single line statements
+ if (project->values(item).isEmpty()) {
+ newValues << item;
+ } else {
+ newValues << project->values(item);
+ }
+ }
+ userRssRules[RSS_TAG_DEFAULT] << newValues;
+
+ // Validate that either both RSS_TAG_NBROFICONS and RSS_TAG_ICONFILE keys exist
+ // or neither of them exist
+ if (!((numberOfIcons.isEmpty() && iconFile.isEmpty()) ||
+ (!numberOfIcons.isEmpty() && !iconFile.isEmpty()))) {
+ numberOfIcons.clear();
+ iconFile.clear();
+ fprintf(stderr, "Warning: Both or neither of '%s%s' and '%s%s' keys must exist.\n",
+ RSS_RULES_BASE, RSS_TAG_NBROFICONS, RSS_RULES_BASE, RSS_TAG_ICONFILE);
+ }
+
+ // Validate that RSS_TAG_NBROFICONS contains only numbers
+ if (!numberOfIcons.isEmpty()) {
+ bool ok;
+ numberOfIcons = numberOfIcons.simplified();
+ numberOfIcons.toInt(&ok);
+ if (!ok) {
+ numberOfIcons.clear();
+ iconFile.clear();
+ fprintf(stderr, "Warning: '%s%s' must be integer in decimal format.\n",
+ RSS_RULES_BASE, RSS_TAG_NBROFICONS);
+ }
+ }
+}
+
+void SymbianCommonGenerator::writeCustomDefFile()
+{
+ if (targetType == TypePlugin && !generator->project->isActiveConfig("stdbinary")) {
+ // Create custom def file for plugin
+ QFile ft(Option::output_dir + QLatin1Char('/') + QLatin1String(PLUGIN_COMMON_DEF_FILE_ACTUAL));
+
+ if (ft.open(QIODevice::WriteOnly)) {
+ generatedFiles << ft.fileName();
+ QTextStream t(&ft);
+
+ t << "; ==============================================================================" << endl;
+ t << "; Generated by qmake (" << qmake_version() << ") (Qt " QT_VERSION_STR ") on: ";
+ t << QDateTime::currentDateTime().toString(Qt::ISODate) << endl;
+ t << "; This file is generated by qmake and should not be modified by the" << endl;
+ t << "; user." << endl;
+ t << "; Name : " PLUGIN_COMMON_DEF_FILE_ACTUAL << endl;
+ t << "; Part of : " << generator->project->values("TARGET").join(" ") << endl;
+ t << "; Description : Fixes common plugin symbols to known ordinals" << endl;
+ t << "; Version : " << endl;
+ t << ";" << endl;
+ t << "; ==============================================================================" << "\n" << endl;
+
+ t << endl;
+
+ t << "EXPORTS" << endl;
+ t << "\tqt_plugin_query_verification_data @ 1 NONAME" << endl;
+ t << "\tqt_plugin_instance @ 2 NONAME" << endl;
+ t << endl;
+ } else {
+ PRINT_FILE_CREATE_ERROR(QString(PLUGIN_COMMON_DEF_FILE_ACTUAL))
+ }
+ }
+}
+
+void SymbianCommonGenerator::parseTsFiles(SymbianLocalizationList *symbianLocalizationList)
+{
+ if (!generator->project->isActiveConfig("localize_deployment")) {
+ return;
+ }
+
+ QStringList symbianTsFiles;
+
+ symbianTsFiles << generator->project->values("SYMBIAN_MATCHED_TRANSLATIONS");
+
+ if (!symbianTsFiles.isEmpty()) {
+ fillQt2SymbianLocalizationList(symbianLocalizationList);
+
+ QMutableListIterator<SymbianLocalization> iter(*symbianLocalizationList);
+ while (iter.hasNext()) {
+ SymbianLocalization &loc = iter.next();
+ static QString matchStrTemplate = QLatin1String(".*_%1\\.ts");
+ QString matchStr = matchStrTemplate.arg(loc.qtLanguageCode);
+
+ foreach (QString file, symbianTsFiles) {
+ QRegExp matcher(matchStr);
+ if (matcher.exactMatch(file) && parseTsContent(file, &loc))
+ break;
+ }
+ }
+ }
+}
+
+void SymbianCommonGenerator::fillQt2SymbianLocalizationList(SymbianLocalizationList *symbianLocalizationList)
+{
+ static QString symbianCodePrefix = QLatin1String("SYMBIAN_LANG.");
+
+ QStringList symbianLanguages = generator->project->values("SYMBIAN_MATCHED_LANGUAGES");
+
+ foreach (QString qtCode, symbianLanguages) {
+ SymbianLocalization newLoc;
+ QString symbianCodeVariable = symbianCodePrefix + qtCode;
+ newLoc.symbianLanguageCode = generator->project->first(symbianCodeVariable);
+ if (!newLoc.symbianLanguageCode.isEmpty()) {
+ newLoc.qtLanguageCode = qtCode;
+ symbianLocalizationList->append(newLoc);
+ }
+ }
+}
+
+void SymbianCommonGenerator::parsePreRules(const QString &deploymentVariable,
+ const QString &variableSuffix,
+ QStringList *rawRuleList,
+ QStringList *languageRuleList,
+ QStringList *headerRuleList,
+ QStringList *vendorRuleList)
+{
+ QMakeProject *project = generator->project;
+ foreach(QString pkgrulesItem, project->values(deploymentVariable + ".pkg_prerules" + variableSuffix)) {
+ QStringList pkgrulesValue = project->values(pkgrulesItem);
+ // If there is no stringlist defined for a rule, use rule name directly
+ // This is convenience for defining single line statements
+ if (pkgrulesValue.isEmpty()) {
+ if (pkgrulesItem.startsWith("&"))
+ *languageRuleList << pkgrulesItem;
+ else if (pkgrulesItem.startsWith("#"))
+ *headerRuleList << pkgrulesItem;
+ else if (pkgrulesItem.startsWith("%") || pkgrulesItem.startsWith(":"))
+ *vendorRuleList << pkgrulesItem;
+ else
+ *rawRuleList << pkgrulesItem;
+ } else {
+ if (containsStartWithItem('&', pkgrulesValue)) {
+ foreach(QString pkgrule, pkgrulesValue) {
+ *languageRuleList << pkgrule;
+ }
+ } else if (containsStartWithItem('#', pkgrulesValue)) {
+ foreach(QString pkgrule, pkgrulesValue) {
+ *headerRuleList << pkgrule;
+ }
+ } else if (containsStartWithItem('%', pkgrulesValue)
+ || containsStartWithItem(':', pkgrulesValue)) {
+ foreach(QString pkgrule, pkgrulesValue) {
+ *vendorRuleList << pkgrule;
+ }
+ } else {
+ foreach(QString pkgrule, pkgrulesValue) {
+ *rawRuleList << pkgrule;
+ }
+ }
+ }
+ }
+}
+
+void SymbianCommonGenerator::parsePostRules(const QString &deploymentVariable,
+ const QString &variableSuffix,
+ QStringList *rawRuleList)
+{
+ QMakeProject *project = generator->project;
+ foreach(QString pkgrulesItem, project->values(deploymentVariable + ".pkg_postrules" + variableSuffix)) {
+ QStringList pkgrulesValue = project->values(pkgrulesItem);
+ // If there is no stringlist defined for a rule, use rule name directly
+ // This is convenience for defining single line statements
+ if (pkgrulesValue.isEmpty()) {
+ *rawRuleList << pkgrulesItem;
+ } else {
+ foreach(QString pkgrule, pkgrulesValue) {
+ *rawRuleList << pkgrule;
+ }
+ }
+ }
+}
+
+bool SymbianCommonGenerator::parseTsContent(const QString &tsFilename, SymbianLocalization *loc)
+{
+ bool retval = true;
+ QMakeProject *project = generator->project;
+ QFile tsFile(tsFilename);
+
+ if (tsFile.exists()) {
+ if (tsFile.open(QIODevice::ReadOnly)) {
+ static QString applicationCaptionsContext = QLatin1String("QtApplicationCaptions");
+ static QString pkgNameContext = QLatin1String("QtPackageNames");
+ static QString tsElement = QLatin1String("TS");
+ static QString contextElement = QLatin1String("context");
+ static QString nameElement = QLatin1String("name");
+ static QString messageElement = QLatin1String("message");
+ static QString sourceElement = QLatin1String("source");
+ static QString translationElement = QLatin1String("translation");
+ static QString shortCaptionId = QLatin1String("Application short caption");
+ static QString longCaptionId = QLatin1String("Application long caption");
+ static QString pkgDisplayNameId = QLatin1String("Package name");
+ static QString installerPkgDisplayNameId = QLatin1String("Smart installer package name");
+ static QString languageAttribute = QLatin1String("language");
+ static QChar underscoreChar = QLatin1Char('_');
+
+ enum CurrentContext {
+ ContextUnknown,
+ ContextUninteresting,
+ ContextInteresting
+ };
+
+ QXmlStreamReader xml(&tsFile);
+
+ while (!xml.atEnd() && xml.name() != tsElement)
+ xml.readNextStartElement();
+
+ while (xml.readNextStartElement()) {
+ if (xml.name() == contextElement) {
+ CurrentContext currentContext = ContextUnknown;
+ while (xml.readNextStartElement()) {
+ if (currentContext == ContextUnknown) {
+ // Expect name element before message elements
+ if (xml.name() == nameElement) {
+ QString nameText = xml.readElementText();
+ if (nameText == applicationCaptionsContext || nameText == pkgNameContext) {
+ currentContext = ContextInteresting;
+ } else {
+ currentContext = ContextUninteresting;
+ }
+ } else {
+ xml.skipCurrentElement();
+ }
+ } else if (currentContext == ContextInteresting) {
+ if (xml.name() == messageElement) {
+ QString source;
+ QString translation;
+ while (xml.readNextStartElement()) {
+ if (xml.name() == sourceElement) {
+ source = xml.readElementText();
+ } else if (xml.name() == translationElement) {
+ translation = xml.readElementText();
+ } else {
+ xml.skipCurrentElement();
+ }
+ }
+
+ if (source == shortCaptionId) {
+ if (loc->shortCaption.isEmpty()) {
+ loc->shortCaption = translation;
+ } else {
+ fprintf(stderr, "Warning: Duplicate application short caption defined in (%s).\n",
+ qPrintable(tsFilename));
+ }
+ } else if (source == longCaptionId) {
+ if (loc->longCaption.isEmpty()) {
+ loc->longCaption = translation;
+ } else {
+ fprintf(stderr, "Warning: Duplicate application long caption defined in (%s).\n",
+ qPrintable(tsFilename));
+ }
+ } else if (source == pkgDisplayNameId) {
+ if (loc->pkgDisplayName.isEmpty()) {
+ loc->pkgDisplayName = translation;
+ } else {
+ fprintf(stderr, "Warning: Duplicate package display name defined in (%s).\n",
+ qPrintable(tsFilename));
+ }
+ } else if (source == installerPkgDisplayNameId) {
+ if (loc->installerPkgDisplayName.isEmpty()) {
+ loc->installerPkgDisplayName = translation;
+ } else {
+ fprintf(stderr, "Warning: Duplicate smart installer package display name defined in (%s).\n",
+ qPrintable(tsFilename));
+ }
+ }
+ } else {
+ xml.skipCurrentElement();
+ }
+ } else {
+ xml.skipCurrentElement();
+ }
+ }
+ } else {
+ xml.skipCurrentElement();
+ }
+ }
+ if (xml.hasError()) {
+ retval = false;
+ fprintf(stderr, "ERROR: Encountered error \"%s\" when parsing ts file (%s).\n",
+ qPrintable(xml.errorString()), qPrintable(tsFilename));
+ }
+ } else {
+ retval = false;
+ fprintf(stderr, "Warning: Could not open ts file (%s).\n", qPrintable(tsFilename));
+ }
+ } else {
+ retval = false;
+ fprintf(stderr, "Warning: ts file does not exist: (%s), unable to parse it.\n",
+ qPrintable(tsFilename));
+ }
+
+ return retval;
+}
+
+QString SymbianCommonGenerator::generatePkgNameForHeader(const SymbianLocalizationList &symbianLocalizationList,
+ const QString &defaultName,
+ bool isForSmartInstaller)
+{
+ QStringList allNames;
+ QString noTranslation = defaultName;
+
+ if (isForSmartInstaller)
+ noTranslation += QLatin1String(" installer");
+
+ SymbianLocalizationListIterator iter(symbianLocalizationList);
+ while (iter.hasNext()) {
+ const SymbianLocalization &loc = iter.next();
+ QString currentName;
+ if (isForSmartInstaller) {
+ currentName = loc.installerPkgDisplayName;
+ } else {
+ currentName = loc.pkgDisplayName;
+ }
+
+ if (currentName.isEmpty())
+ currentName = noTranslation;
+
+ allNames << currentName;
+ }
+
+ if (!allNames.size())
+ allNames << noTranslation;
+
+ return allNames.join("\",\"");
+
+}
+
+void SymbianCommonGenerator::addLocalizedResourcesToDeployment(const QString &deploymentFilesVar,
+ const SymbianLocalizationList &symbianLocalizationList)
+{
+ QStringList locResources;
+ foreach (QString defaultResource, generator->project->values(deploymentFilesVar)) {
+ if (defaultResource.endsWith(".rsc")) {
+ defaultResource.chop(2);
+ SymbianLocalizationListIterator iter(symbianLocalizationList);
+ while (iter.hasNext()) {
+ const SymbianLocalization &loc = iter.next();
+ locResources << QString(defaultResource + loc.symbianLanguageCode);
+ }
+ }
+ }
+ generator->project->values(deploymentFilesVar) << locResources;
+}
+
+QString SymbianCommonGenerator::generateLocFileName()
+{
+ QString fileName(fixedTarget);
+ if (!Option::output_dir.isEmpty())
+ fileName = Option::output_dir + QLatin1Char('/') + fileName;
+ fileName.append(".loc");
+ return fileName;
+}
diff --git a/qmake/generators/symbian/symbiancommon.h b/qmake/generators/symbian/symbiancommon.h
new file mode 100644
index 0000000000..5182021439
--- /dev/null
+++ b/qmake/generators/symbian/symbiancommon.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYMBIANCOMMON_H
+#define SYMBIANCOMMON_H
+
+#include <project.h>
+#include <makefile.h>
+#include "initprojectdeploy_symbian.h"
+
+#define PRINT_FILE_CREATE_ERROR(filename) fprintf(stderr, "Error: Could not create '%s'\n", qPrintable(filename));
+
+class SymbianLocalization
+{
+public:
+ QString qtLanguageCode;
+ QString symbianLanguageCode;
+ QString shortCaption;
+ QString longCaption;
+ QString pkgDisplayName;
+ QString installerPkgDisplayName;
+};
+
+typedef QList<SymbianLocalization> SymbianLocalizationList;
+typedef QListIterator<SymbianLocalization> SymbianLocalizationListIterator;
+
+class SymbianCommonGenerator
+{
+public:
+ enum TargetType {
+ TypeExe,
+ TypeDll,
+ TypeLib,
+ TypePlugin,
+ TypeSubdirs
+ };
+
+
+ SymbianCommonGenerator(MakefileGenerator *generator);
+
+ virtual void init();
+
+protected:
+
+ QString removePathSeparators(QString &file);
+ void removeSpecialCharacters(QString& str);
+ void generatePkgFile(const QString &iconFile,
+ bool epocBuild,
+ const SymbianLocalizationList &symbianLocalizationList);
+ bool containsStartWithItem(const QChar &c, const QStringList& src);
+
+ void writeRegRssFile(QMap<QString, QStringList> &useritems);
+ void writeRegRssList(QTextStream &t, QStringList &userList,
+ const QString &listTag,
+ const QString &listItem);
+ void writeRssFile(QString &numberOfIcons, QString &iconfile);
+ void writeLocFile(const SymbianLocalizationList &symbianLocalizationList);
+ void readRssRules(QString &numberOfIcons,
+ QString &iconFile,
+ QMap<QString, QStringList> &userRssRules);
+
+ void writeCustomDefFile();
+
+ void parseTsFiles(SymbianLocalizationList *symbianLocalizationList);
+ void fillQt2SymbianLocalizationList(SymbianLocalizationList *symbianLocalizationList);
+
+ void parsePreRules(const QString &deploymentVariable,
+ const QString &variableSuffix,
+ QStringList *rawRuleList,
+ QStringList *languageRuleList,
+ QStringList *headerRuleList,
+ QStringList *vendorRuleList);
+ void parsePostRules(const QString &deploymentVariable,
+ const QString &variableSuffix,
+ QStringList *rawRuleList);
+ bool parseTsContent(const QString &tsFilename, SymbianLocalization *loc);
+ QString generatePkgNameForHeader(const SymbianLocalizationList &symbianLocalizationList,
+ const QString &defaultName,
+ bool isForSmartInstaller);
+ void addLocalizedResourcesToDeployment(const QString &deploymentFilesVar,
+ const SymbianLocalizationList &symbianLocalizationList);
+ QString generateLocFileName();
+
+protected:
+ MakefileGenerator *generator;
+
+ QStringList generatedFiles;
+ QStringList generatedDirs;
+ QString fixedTarget;
+ QString privateDirUid;
+ QString uid3;
+ TargetType targetType;
+};
+
+#endif // SYMBIANCOMMON_H
diff --git a/qmake/generators/symbian/symmake.cpp b/qmake/generators/symbian/symmake.cpp
new file mode 100644
index 0000000000..08d33700f7
--- /dev/null
+++ b/qmake/generators/symbian/symmake.cpp
@@ -0,0 +1,1136 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "symmake.h"
+
+#include <qstring.h>
+#include <qhash.h>
+#include <qstringlist.h>
+#include <qdir.h>
+#include <qdatetime.h>
+#include <stdlib.h>
+#include <qdebug.h>
+
+// Included from tools/shared
+#include <symbian/epocroot_p.h>
+
+#define RESOURCE_DIRECTORY_MMP "/resource/apps"
+#define REGISTRATION_RESOURCE_DIRECTORY_HW "/private/10003a3f/import/apps"
+#define PLUGIN_COMMON_DEF_FILE_FOR_MMP "./plugin_common.def"
+#define BLD_INF_FILENAME_LEN (sizeof(BLD_INF_FILENAME) - 1)
+
+#define BLD_INF_RULES_BASE "BLD_INF_RULES."
+#define BLD_INF_TAG_PLATFORMS "prj_platforms"
+#define BLD_INF_TAG_MMPFILES "prj_mmpfiles"
+#define BLD_INF_TAG_TESTMMPFILES "prj_testmmpfiles"
+#define BLD_INF_TAG_EXTENSIONS "prj_extensions"
+#define BLD_INF_TAG_TESTEXTENSIONS "prj_testextensions"
+
+#define MMP_TARGET "TARGET"
+#define MMP_TARGETTYPE "TARGETTYPE"
+#define MMP_SECUREID "SECUREID"
+#define MMP_OPTION "OPTION"
+#define MMP_LINKEROPTION "LINKEROPTION"
+#define MMP_CAPABILITY "CAPABILITY"
+#define MMP_EPOCALLOWDLLDATA "EPOCALLOWDLLDATA"
+#define MMP_EPOCHEAPSIZE "EPOCHEAPSIZE"
+#define MMP_EPOCSTACKSIZE "EPOCSTACKSIZE"
+#define MMP_UID "UID"
+#define MMP_VENDORID "VENDORID"
+#define MMP_VERSION "VERSION"
+#define MMP_START_RESOURCE "START RESOURCE"
+#define MMP_END_RESOURCE "END"
+
+#define VAR_CXXFLAGS "QMAKE_CXXFLAGS"
+#define VAR_CFLAGS "QMAKE_CFLAGS"
+#define VAR_LFLAGS "QMAKE_LFLAGS"
+
+#define DEFINE_REPLACE_REGEXP "[^A-Z0-9_]"
+
+QString SymbianMakefileGenerator::fixPathForMmp(const QString& origPath, const QDir& parentDir)
+{
+ static QString epocRootStr;
+ if (epocRootStr.isEmpty()) {
+ epocRootStr = qt_epocRoot();
+ QFileInfo efi(epocRootStr);
+ if (!efi.exists() || epocRootStr.isEmpty()) {
+ fprintf(stderr, "Unable to resolve epocRoot '%s' to real dir on current drive, defaulting to '/' for mmp paths\n", qPrintable(qt_epocRoot()));
+ epocRootStr = "/";
+ } else {
+ epocRootStr = efi.absoluteFilePath();
+ }
+ if (!epocRootStr.endsWith("/"))
+ epocRootStr += "/";
+
+ epocRootStr += "epoc32/";
+ }
+
+ QString resultPath = origPath;
+
+ // Make it relative, unless it starts with "%epocroot%/epoc32/"
+ if (resultPath.startsWith(epocRootStr, Qt::CaseInsensitive)) {
+ resultPath.replace(epocRootStr, "/epoc32/", Qt::CaseInsensitive);
+ } else {
+ resultPath = parentDir.relativeFilePath(resultPath);
+ }
+ resultPath = QDir::cleanPath(resultPath);
+
+ if (resultPath.isEmpty())
+ resultPath = ".";
+
+ return resultPath;
+}
+
+QString SymbianMakefileGenerator::absolutizePath(const QString& origPath)
+{
+ // Prepend epocroot to any paths beginning with "/epoc32/"
+ QString resultPath = QDir::fromNativeSeparators(origPath);
+ if (resultPath.startsWith("/epoc32/", Qt::CaseInsensitive))
+ resultPath = QDir::fromNativeSeparators(qt_epocRoot()) + resultPath.mid(1);
+
+ QFileInfo fi(fileInfo(resultPath));
+
+ // Since origPath can be something given in HEADERS, we need to check if we are dealing
+ // with a file or a directory. In case the origPath doesn't yet exist, isFile() returns
+ // false and we default to assuming it is a dir.
+ if (fi.isFile()) {
+ resultPath = fi.absolutePath();
+ } else {
+ resultPath = fi.absoluteFilePath();
+ }
+
+ resultPath = QDir::cleanPath(resultPath);
+
+ return resultPath;
+}
+
+SymbianMakefileGenerator::SymbianMakefileGenerator() : MakefileGenerator(), SymbianCommonGenerator(this) { }
+SymbianMakefileGenerator::~SymbianMakefileGenerator() { }
+
+void SymbianMakefileGenerator::writeHeader(QTextStream &t)
+{
+ t << "// ============================================================================" << endl;
+ t << "// * Makefile for building: " << escapeFilePath(var("TARGET")) << endl;
+ t << "// * Generated by qmake (" << qmake_version() << ") (Qt " QT_VERSION_STR ") on: ";
+ t << QDateTime::currentDateTime().toString(Qt::ISODate) << endl;
+ t << "// * This file is generated by qmake and should not be modified by the" << endl;
+ t << "// * user." << endl;
+ t << "// * Project: " << fileFixify(project->projectFile()) << endl;
+ t << "// * Template: " << var("TEMPLATE") << endl;
+ t << "// ============================================================================" << endl;
+ t << endl;
+
+ // Defining define for bld.inf
+
+ QString shortProFilename = project->projectFile();
+ shortProFilename.replace(0, shortProFilename.lastIndexOf("/") + 1, QString(""));
+ shortProFilename.replace(Option::pro_ext, QString(""));
+
+ QString bldinfDefine = shortProFilename;
+ bldinfDefine.append("_");
+ bldinfDefine.append(generate_uid(project->projectFile()));
+ bldinfDefine = bldinfDefine.toUpper();
+
+ // replace anything not alphanumeric with underscore
+ QRegExp replacementMask(DEFINE_REPLACE_REGEXP);
+ bldinfDefine.replace(replacementMask, QLatin1String("_"));
+
+ bldinfDefine.prepend("BLD_INF_");
+
+ t << "#define " << bldinfDefine << endl << endl;
+}
+
+bool SymbianMakefileGenerator::writeMakefile(QTextStream &t)
+{
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ fprintf(stderr, "Project files not generated because all requirements are not met:\n\t%s\n",
+ qPrintable(var("QMAKE_FAILED_REQUIREMENTS")));
+ return false;
+ }
+
+ writeHeader(t);
+
+ QString numberOfIcons;
+ QString iconFile;
+ QMap<QString, QStringList> userRssRules;
+ readRssRules(numberOfIcons, iconFile, userRssRules);
+
+ SymbianLocalizationList symbianLocalizationList;
+ parseTsFiles(&symbianLocalizationList);
+
+ // Generate pkg files if there are any actual files to deploy
+ bool generatePkg = false;
+
+ if (targetType == TypeExe) {
+ generatePkg = true;
+ } else {
+ foreach(QString item, project->values("DEPLOYMENT")) {
+ // ### Qt 5: remove .sources, inconsistent with INSTALLS
+ if (!project->values(item + ".sources").isEmpty() ||
+ !project->values(item + ".files").isEmpty()) {
+ generatePkg = true;
+ break;
+ }
+ }
+ }
+
+ if (generatePkg) {
+ generatePkgFile(iconFile, true, symbianLocalizationList);
+ }
+
+ writeBldInfContent(t, generatePkg, iconFile);
+
+ // Generate empty wrapper makefile here, because wrapper makefile must exist before writeMkFile,
+ // but all required data is not yet available.
+ bool isPrimaryMakefile = true;
+ QString wrapperFileName = Option::output_dir + QLatin1Char('/') + QLatin1String("Makefile");
+ QString outputFileName = fileInfo(Option::output.fileName()).fileName();
+ if (outputFileName != BLD_INF_FILENAME) {
+ wrapperFileName.append(".").append(outputFileName.startsWith(BLD_INF_FILENAME)
+ ? outputFileName.mid(sizeof(BLD_INF_FILENAME))
+ : outputFileName);
+ isPrimaryMakefile = false;
+ }
+
+ QFile wrapperMakefile(wrapperFileName);
+ if (wrapperMakefile.open(QIODevice::WriteOnly)) {
+ generatedFiles << wrapperFileName;
+ } else {
+ PRINT_FILE_CREATE_ERROR(wrapperFileName);
+ return false;
+ }
+
+ if (targetType == TypeSubdirs) {
+ // If we have something to deploy, generate extension makefile for just that, since
+ // normal extension makefile is not getting generated and we need emulator deployment to be done.
+ if (generatePkg)
+ writeMkFile(wrapperFileName, true);
+ writeWrapperMakefile(wrapperMakefile, isPrimaryMakefile);
+ return true;
+ }
+
+ writeMkFile(wrapperFileName, false);
+
+ QString absoluteMmpFileName = Option::output_dir + QLatin1Char('/') + mmpFileName;
+ writeMmpFile(absoluteMmpFileName, symbianLocalizationList);
+
+ if (targetType == TypeExe) {
+ if (!project->isActiveConfig("no_icon")) {
+ writeRegRssFile(userRssRules);
+ writeRssFile(numberOfIcons, iconFile);
+ writeLocFile(symbianLocalizationList);
+ }
+ }
+
+ writeCustomDefFile();
+ writeWrapperMakefile(wrapperMakefile, isPrimaryMakefile);
+
+ return true;
+}
+
+void SymbianMakefileGenerator::init()
+{
+ MakefileGenerator::init();
+ SymbianCommonGenerator::init();
+
+ if (0 != project->values("QMAKE_PLATFORM").size())
+ platform = varGlue("QMAKE_PLATFORM", "", " ", "");
+
+ if (0 == project->values("QMAKESPEC").size())
+ project->values("QMAKESPEC").append(qgetenv("QMAKESPEC"));
+
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
+ project->values("QMAKE_LIBS_PRIVATE") += escapeFilePaths(project->values("LIBS_PRIVATE"));
+
+ // Disallow renaming of bld.inf.
+ project->values("MAKEFILE").clear();
+ project->values("MAKEFILE") += BLD_INF_FILENAME;
+
+ // .mmp
+ mmpFileName = fixedTarget;
+ if (targetType == TypeExe)
+ mmpFileName.append("_exe");
+ else if (targetType == TypeDll || targetType == TypePlugin)
+ mmpFileName.append("_dll");
+ else if (targetType == TypeLib)
+ mmpFileName.append("_lib");
+ mmpFileName.append(Option::mmp_ext);
+
+ initMmpVariables();
+
+ uid2 = project->first("TARGET.UID2");
+
+ uid2 = uid2.trimmed();
+}
+
+QString SymbianMakefileGenerator::getTargetExtension()
+{
+ QString ret;
+ if (targetType == TypeExe) {
+ ret.append("exe");
+ } else if (targetType == TypeLib) {
+ ret.append("lib");
+ } else if (targetType == TypeDll || targetType == TypePlugin) {
+ ret.append("dll");
+ } else if (targetType == TypeSubdirs) {
+ // Not actually usable, so return empty
+ } else {
+ // If nothing else set, default to exe
+ ret.append("exe");
+ }
+
+ return ret;
+}
+
+QString SymbianMakefileGenerator::generateUID3()
+{
+ QString target = project->first("TARGET");
+ QString currPath = qmake_getpwd();
+ target.prepend("/").prepend(currPath);
+ return generate_test_uid(target);
+}
+
+void SymbianMakefileGenerator::initMmpVariables()
+{
+ QStringList sysincspaths;
+ QStringList srcincpaths;
+ QStringList srcpaths;
+
+ srcpaths << project->values("SOURCES") << project->values("GENERATED_SOURCES");
+ srcpaths << project->values("UNUSED_SOURCES") << project->values("UI_SOURCES_DIR");
+ srcpaths << project->values("UI_DIR");
+
+ QDir current = QDir::current();
+ QString absolutizedCurrent = absolutizePath(".");
+
+ for (int j = 0; j < srcpaths.size(); ++j) {
+ QFileInfo fi(fileInfo(srcpaths.at(j)));
+ // Sometimes sources have other than *.c* files (e.g. *.moc); prune them.
+ if (fi.suffix().startsWith("c")) {
+ if (fi.filePath().length() > fi.fileName().length()) {
+ appendIfnotExist(srcincpaths, fi.path());
+ sources[absolutizePath(fi.path())] += fi.fileName();
+ } else {
+ sources[absolutizedCurrent] += fi.fileName();
+ appendIfnotExist(srcincpaths, absolutizedCurrent);
+ }
+ }
+ }
+
+ QStringList incpaths;
+ incpaths << project->values("INCLUDEPATH");
+ incpaths << QLibraryInfo::location(QLibraryInfo::HeadersPath);
+ incpaths << project->values("HEADERS");
+ incpaths << srcincpaths;
+ incpaths << project->values("UI_HEADERS_DIR");
+ incpaths << project->values("UI_DIR");
+
+ for (int j = 0; j < incpaths.size(); ++j) {
+ QString includepath = absolutizePath(incpaths.at(j));
+ appendIfnotExist(sysincspaths, includepath);
+ appendAbldTempDirs(sysincspaths, includepath);
+ }
+
+ // Remove duplicate include path entries
+ QStringList temporary;
+ for (int i = 0; i < sysincspaths.size(); ++i) {
+ QString origPath = sysincspaths.at(i);
+ QFileInfo origPathInfo(fileInfo(origPath));
+ bool bFound = false;
+
+ for (int j = 0; j < temporary.size(); ++j) {
+ QString tmpPath = temporary.at(j);
+ QFileInfo tmpPathInfo(fileInfo(tmpPath));
+
+ if (origPathInfo.absoluteFilePath() == tmpPathInfo.absoluteFilePath()) {
+ bFound = true;
+ if (!tmpPathInfo.isRelative() && origPathInfo.isRelative()) {
+ // We keep the relative notation
+ temporary.removeOne(tmpPath);
+ temporary << origPath;
+ }
+ }
+ }
+
+ if (!bFound)
+ temporary << origPath;
+
+ }
+
+ sysincspaths.clear();
+ sysincspaths << temporary;
+
+ systeminclude.insert("SYSTEMINCLUDE", sysincspaths);
+
+ // Check MMP_RULES for singleton keywords that are overridden
+ QStringList overridableMmpKeywords;
+ QStringList restrictableMmpKeywords;
+ QStringList restrictedMmpKeywords;
+ bool inResourceBlock = false;
+
+ overridableMmpKeywords << QLatin1String(MMP_TARGETTYPE) << QLatin1String(MMP_EPOCHEAPSIZE);
+ restrictableMmpKeywords << QLatin1String(MMP_TARGET) << QLatin1String(MMP_SECUREID)
+ << QLatin1String(MMP_OPTION) << QLatin1String(MMP_LINKEROPTION)
+ << QLatin1String(MMP_CAPABILITY) << QLatin1String(MMP_EPOCALLOWDLLDATA)
+ << QLatin1String(MMP_EPOCSTACKSIZE) << QLatin1String(MMP_UID)
+ << QLatin1String(MMP_VENDORID) << QLatin1String(MMP_VERSION);
+
+ foreach (QString item, project->values("MMP_RULES")) {
+ if (project->values(item).isEmpty()) {
+ handleMmpRulesOverrides(item, inResourceBlock, restrictedMmpKeywords,
+ restrictableMmpKeywords, overridableMmpKeywords);
+ } else {
+ foreach (QString itemRow, project->values(item)) {
+ handleMmpRulesOverrides(itemRow, inResourceBlock, restrictedMmpKeywords,
+ restrictableMmpKeywords, overridableMmpKeywords);
+ }
+ }
+ }
+
+ if (restrictedMmpKeywords.size()) {
+ fprintf(stderr, "Warning: Restricted statements detected in MMP_RULES:\n"
+ " (%s)\n"
+ " Use corresponding qmake variable(s) instead.\n",
+ qPrintable(restrictedMmpKeywords.join(", ")));
+ }
+}
+
+void SymbianMakefileGenerator::handleMmpRulesOverrides(QString &checkString,
+ bool &inResourceBlock,
+ QStringList &restrictedMmpKeywords,
+ const QStringList &restrictableMmpKeywords,
+ const QStringList &overridableMmpKeywords)
+{
+ QString simplifiedString = checkString.simplified();
+
+ if (!inResourceBlock && simplifiedString.startsWith(MMP_START_RESOURCE, Qt::CaseInsensitive))
+ inResourceBlock = true;
+ else if (inResourceBlock && simplifiedString.startsWith(MMP_END_RESOURCE, Qt::CaseInsensitive))
+ inResourceBlock = false;
+
+ // Allow restricted and overridable items in RESOURCE blocks as those do not actually
+ // override anything.
+ if (!inResourceBlock) {
+ appendKeywordIfMatchFound(overriddenMmpKeywords, overridableMmpKeywords, simplifiedString);
+ appendKeywordIfMatchFound(restrictedMmpKeywords, restrictableMmpKeywords, simplifiedString);
+ }
+}
+
+void SymbianMakefileGenerator::appendKeywordIfMatchFound(QStringList &list,
+ const QStringList &keywordList,
+ QString &checkString)
+{
+ // Check if checkString starts with any supplied keyword and
+ // add the found keyword to list if it does.
+ foreach (QString item, keywordList) {
+ if (checkString.startsWith(QString(item).append(" "), Qt::CaseInsensitive)
+ || checkString.compare(item, Qt::CaseInsensitive) == 0) {
+ appendIfnotExist(list, item);
+ }
+ }
+}
+
+
+bool SymbianMakefileGenerator::removeDuplicatedStrings(QStringList &stringList)
+{
+ QStringList tmpStringList;
+
+ for (int i = 0; i < stringList.size(); ++i) {
+ QString string = stringList.at(i);
+ if (tmpStringList.contains(string))
+ continue;
+ else
+ tmpStringList.append(string);
+ }
+
+ stringList.clear();
+ stringList = tmpStringList;
+ return true;
+}
+
+void SymbianMakefileGenerator::writeMmpFileHeader(QTextStream &t)
+{
+ t << "// ==============================================================================" << endl;
+ t << "// Generated by qmake (" << qmake_version() << ") (Qt " QT_VERSION_STR ") on: ";
+ t << QDateTime::currentDateTime().toString(Qt::ISODate) << endl;
+ t << "// This file is generated by qmake and should not be modified by the" << endl;
+ t << "// user." << endl;
+ t << "// Name : " << mmpFileName << endl;
+ t << "// ==============================================================================" << endl << endl;
+}
+
+void SymbianMakefileGenerator::writeMmpFile(QString &filename, const SymbianLocalizationList &symbianLocalizationList)
+{
+ QFile ft(filename);
+ if (ft.open(QIODevice::WriteOnly)) {
+ generatedFiles << ft.fileName();
+
+ QTextStream t(&ft);
+
+ writeMmpFileHeader(t);
+
+ writeMmpFileTargetPart(t);
+
+ writeMmpFileResourcePart(t, symbianLocalizationList);
+
+ writeMmpFileMacrosPart(t);
+
+ writeMmpFileIncludePart(t);
+
+ QDir current = QDir::current();
+
+ for (QMap<QString, QStringList>::iterator it = sources.begin(); it != sources.end(); ++it) {
+ QStringList values = it.value();
+ QString currentSourcePath = it.key();
+
+ if (values.size())
+ t << "SOURCEPATH \t" << fixPathForMmp(currentSourcePath, current) << endl;
+
+ for (int i = 0; i < values.size(); ++i) {
+ QString sourceFileName = values.at(i);
+ t << "SOURCE\t\t" << sourceFileName << endl;
+ }
+ t << endl;
+ }
+ t << endl;
+
+ if (!project->isActiveConfig("static") && !project->isActiveConfig("staticlib")) {
+ writeMmpFileLibraryPart(t);
+ }
+
+ writeMmpFileCapabilityPart(t);
+
+ writeMmpFileCompilerOptionPart(t);
+
+ writeMmpFileBinaryVersionPart(t);
+
+ writeMmpFileRulesPart(t);
+ } else {
+ PRINT_FILE_CREATE_ERROR(filename)
+ }
+}
+
+void SymbianMakefileGenerator::writeMmpFileMacrosPart(QTextStream& t)
+{
+ t << endl;
+
+ QStringList &defines = project->values("DEFINES");
+ if (defines.size())
+ t << "// Qt Macros" << endl;
+ for (int i = 0; i < defines.size(); ++i) {
+ QString def = defines.at(i);
+ addMacro(t, def);
+ }
+
+ // These are required in order that all methods will be correctly exported e.g from qtestlib
+ QStringList &exp_defines = project->values("PRL_EXPORT_DEFINES");
+ if (exp_defines.size())
+ t << endl << "// Qt Export Defines" << endl;
+ for (int i = 0; i < exp_defines.size(); ++i) {
+ QString def = exp_defines.at(i);
+ addMacro(t, def);
+ }
+
+ t << endl;
+}
+
+void SymbianMakefileGenerator::addMacro(QTextStream& t, const QString& value)
+{
+ t << "MACRO\t\t" << value << endl;
+}
+
+
+void SymbianMakefileGenerator::writeMmpFileTargetPart(QTextStream& t)
+{
+ bool skipTargetType = overriddenMmpKeywords.contains(MMP_TARGETTYPE);
+ bool skipEpocHeapSize = overriddenMmpKeywords.contains(MMP_EPOCHEAPSIZE);
+
+ if (targetType == TypeExe) {
+ t << MMP_TARGET "\t\t" << fixedTarget << ".exe" << endl;
+ if (!skipTargetType) {
+ if (project->isActiveConfig("stdbinary"))
+ t << MMP_TARGETTYPE "\t\tSTDEXE" << endl;
+ else
+ t << MMP_TARGETTYPE "\t\tEXE" << endl;
+ }
+ } else if (targetType == TypeDll || targetType == TypePlugin) {
+ t << MMP_TARGET "\t\t" << fixedTarget << ".dll" << endl;
+ if (!skipTargetType) {
+ if (project->isActiveConfig("stdbinary"))
+ t << MMP_TARGETTYPE "\t\tSTDDLL" << endl;
+ else
+ t << MMP_TARGETTYPE "\t\tDLL" << endl;
+ }
+ } else if (targetType == TypeLib) {
+ t << MMP_TARGET "\t\t" << fixedTarget << ".lib" << endl;
+ if (!skipTargetType) {
+ if (project->isActiveConfig("stdbinary"))
+ t << MMP_TARGETTYPE "\t\tSTDLIB" << endl;
+ else
+ t << MMP_TARGETTYPE "\t\tLIB" << endl;
+ }
+ } else {
+ fprintf(stderr, "Error: Unexpected targettype (%d) in SymbianMakefileGenerator::writeMmpFileTargetPart\n", targetType);
+ }
+
+ t << endl;
+
+ t << MMP_UID "\t\t" << uid2 << " " << uid3 << endl;
+
+ if (0 != project->values("TARGET.SID").size()) {
+ t << MMP_SECUREID "\t\t" << project->values("TARGET.SID").join(" ") << endl;
+ } else {
+ if (0 == uid3.size())
+ t << MMP_SECUREID "\t\t0" << endl;
+ else
+ t << MMP_SECUREID "\t\t" << uid3 << endl;
+ }
+
+ // default value used from mkspecs is 0
+ if (0 != project->values("TARGET.VID").size()) {
+ t << MMP_VENDORID "\t\t" << project->values("TARGET.VID").join(" ") << endl;
+ }
+
+ t << endl;
+
+ if (0 != project->first("TARGET.EPOCSTACKSIZE").size())
+ t << MMP_EPOCSTACKSIZE "\t\t" << project->first("TARGET.EPOCSTACKSIZE") << endl;
+ if (!skipEpocHeapSize && 0 != project->values("TARGET.EPOCHEAPSIZE").size())
+ t << MMP_EPOCHEAPSIZE "\t\t" << project->values("TARGET.EPOCHEAPSIZE").join(" ") << endl;
+ if (0 != project->values("TARGET.EPOCALLOWDLLDATA").size())
+ t << MMP_EPOCALLOWDLLDATA << endl;
+
+ if (targetType == TypePlugin && !project->isActiveConfig("stdbinary")) {
+ // Use custom def file for Qt plugins
+ t << "DEFFILE " PLUGIN_COMMON_DEF_FILE_FOR_MMP << endl;
+ }
+
+ t << endl;
+}
+
+
+/*
+ Application registration resource files should be installed to the
+ \private\10003a3f\import\apps directory.
+*/
+void SymbianMakefileGenerator::writeMmpFileResourcePart(QTextStream& t, const SymbianLocalizationList &symbianLocalizationList)
+{
+ if ((targetType == TypeExe) &&
+ !project->isActiveConfig("no_icon")) {
+
+ QString locTarget = fixedTarget;
+ locTarget.append(".rss");
+
+ t << "SOURCEPATH\t\t\t. " << endl;
+ t << "LANG SC "; // no endl
+ SymbianLocalizationListIterator iter(symbianLocalizationList);
+ while (iter.hasNext()) {
+ const SymbianLocalization &loc = iter.next();
+ t << loc.symbianLanguageCode << " "; // no endl
+ }
+ t << endl;
+ t << MMP_START_RESOURCE "\t\t" << locTarget << endl;
+ t << "HEADER" << endl;
+ t << "TARGETPATH\t\t\t" RESOURCE_DIRECTORY_MMP << endl;
+ t << MMP_END_RESOURCE << endl << endl;
+
+ QString regTarget = fixedTarget;
+ regTarget.append("_reg.rss");
+
+ t << "SOURCEPATH\t\t\t." << endl;
+ t << MMP_START_RESOURCE "\t\t" << regTarget << endl;
+ if (isForSymbianSbsv2())
+ t << "DEPENDS " << fixedTarget << ".rsg" << endl;
+ t << "TARGETPATH\t\t" REGISTRATION_RESOURCE_DIRECTORY_HW << endl;
+ t << MMP_END_RESOURCE << endl << endl;
+ }
+}
+
+void SymbianMakefileGenerator::writeMmpFileSystemIncludePart(QTextStream& t)
+{
+ QDir current = QDir::current();
+
+ for (QMap<QString, QStringList>::iterator it = systeminclude.begin(); it != systeminclude.end(); ++it) {
+ QStringList values = it.value();
+ for (int i = 0; i < values.size(); ++i) {
+ QString handledPath = values.at(i);
+ t << "SYSTEMINCLUDE\t\t" << fixPathForMmp(handledPath, current) << endl;
+ }
+ }
+
+ t << endl;
+}
+
+void SymbianMakefileGenerator::writeMmpFileIncludePart(QTextStream& t)
+{
+ writeMmpFileSystemIncludePart(t);
+}
+
+void SymbianMakefileGenerator::writeMmpFileLibraryPart(QTextStream& t)
+{
+ QStringList &libs = project->values("LIBS");
+ libs << project->values("QMAKE_LIBS") << project->values("QMAKE_LIBS_PRIVATE");
+
+ removeDuplicatedStrings(libs);
+
+ for (int i = 0; i < libs.size(); ++i) {
+ QString lib = libs.at(i);
+ // The -L flag is uninteresting, since all symbian libraries exist in the same directory.
+ if (lib.startsWith("-l")) {
+ lib.remove(0, 2);
+ QString mmpStatement;
+ if (lib.endsWith(".lib")) {
+ lib.chop(4);
+ mmpStatement = "STATICLIBRARY\t";
+ } else {
+ if (lib.endsWith(".dll"))
+ lib.chop(4);
+ mmpStatement = "LIBRARY\t\t";
+ }
+ t << mmpStatement << lib << ".lib" << endl;
+ }
+ }
+
+ t << endl;
+}
+
+void SymbianMakefileGenerator::writeMmpFileCapabilityPart(QTextStream& t)
+{
+ if (0 != project->first("TARGET.CAPABILITY").size()) {
+ QStringList &capabilities = project->values("TARGET.CAPABILITY");
+ t << MMP_CAPABILITY "\t\t";
+
+ for (int i = 0; i < capabilities.size(); ++i) {
+ QString cap = capabilities.at(i);
+ t << cap << " ";
+ }
+ } else {
+ t << MMP_CAPABILITY "\t\tNone";
+ }
+ t << endl << endl;
+}
+
+void SymbianMakefileGenerator::writeMmpFileConditionalOptions(QTextStream& t,
+ const QString &optionType,
+ const QString &optionTag,
+ const QString &variableBase)
+{
+ foreach(QString compilerVersion, project->values("VERSION_FLAGS." + optionTag)) {
+ QStringList currentValues = project->values(variableBase + "." + compilerVersion);
+ if (currentValues.size()) {
+ t << "#if defined(" << compilerVersion << ")" << endl;
+ t << optionType << " " << optionTag << " " << currentValues.join(" ") << endl;
+ t << "#endif" << endl;
+ }
+ }
+}
+
+void SymbianMakefileGenerator::writeMmpFileSimpleOption(QTextStream& t,
+ const QString &optionType,
+ const QString &optionTag,
+ const QString &options)
+{
+ QString trimmedOptions = options.trimmed();
+ if (!trimmedOptions.isEmpty())
+ t << optionType << " " << optionTag << " " << trimmedOptions << endl;
+}
+
+void SymbianMakefileGenerator::appendMmpFileOptions(QString &options, const QStringList &list)
+{
+ if (list.size()) {
+ options.append(list.join(" "));
+ options.append(" ");
+ }
+}
+
+void SymbianMakefileGenerator::writeMmpFileCompilerOptionPart(QTextStream& t)
+{
+ QStringList keywords = project->values("MMP_OPTION_KEYWORDS");
+ QStringList commonCxxFlags = project->values(VAR_CXXFLAGS);
+ QStringList commonCFlags = project->values(VAR_CFLAGS);
+ QStringList commonLFlags = project->values(VAR_LFLAGS);
+
+ foreach(QString item, keywords) {
+ QString compilerOption;
+ QString linkerOption;
+
+ appendMmpFileOptions(compilerOption, project->values(VAR_CXXFLAGS "." + item));
+ appendMmpFileOptions(compilerOption, project->values(VAR_CFLAGS "." + item));
+ appendMmpFileOptions(compilerOption, commonCxxFlags);
+ appendMmpFileOptions(compilerOption, commonCFlags);
+
+ appendMmpFileOptions(linkerOption, project->values(VAR_LFLAGS "." + item));
+ appendMmpFileOptions(linkerOption, commonLFlags);
+
+ writeMmpFileSimpleOption(t, MMP_OPTION, item, compilerOption);
+ writeMmpFileSimpleOption(t, MMP_LINKEROPTION, item, linkerOption);
+
+ writeMmpFileConditionalOptions(t, MMP_OPTION, item, VAR_CXXFLAGS);
+ writeMmpFileConditionalOptions(t, MMP_LINKEROPTION, item, VAR_LFLAGS);
+ }
+
+ t << endl;
+}
+
+void SymbianMakefileGenerator::writeMmpFileBinaryVersionPart(QTextStream& t)
+{
+ QString applicationVersion = project->first("VERSION");
+ QStringList verNumList = applicationVersion.split('.');
+ uint major = 0;
+ uint minor = 0;
+ uint patch = 0;
+ bool success = false;
+
+ if (verNumList.size() > 0) {
+ major = verNumList[0].toUInt(&success);
+ if (success && verNumList.size() > 1) {
+ minor = verNumList[1].toUInt(&success);
+ if (success && verNumList.size() > 2) {
+ patch = verNumList[2].toUInt(&success);
+ }
+ }
+ }
+
+ QString mmpVersion;
+ if (success && major <= 0xFFFF && minor <= 0xFF && patch <= 0xFF) {
+ // Symbian binary version only has major and minor components, so compress
+ // Qt's minor and patch values into the minor component. Since Symbian's minor
+ // component is a 16 bit value, only allow 8 bits for each to avoid overflow.
+ mmpVersion.append(QString::number(major))
+ .append('.')
+ .append(QString::number((minor << 8) + patch));
+ } else {
+ if (!applicationVersion.isEmpty())
+ fprintf(stderr, "Invalid VERSION string: %s\n", qPrintable(applicationVersion));
+ mmpVersion = "10.0"; // Default binary version for symbian is 10.0
+ }
+
+ t << MMP_VERSION " " << mmpVersion << endl;
+}
+
+void SymbianMakefileGenerator::writeMmpFileRulesPart(QTextStream& t)
+{
+ foreach(QString item, project->values("MMP_RULES")) {
+ t << endl;
+ // If there is no stringlist defined for a rule, use rule name directly
+ // This is convenience for defining single line mmp statements
+ if (project->values(item).isEmpty()) {
+ t << item << endl;
+ } else {
+ foreach(QString itemRow, project->values(item)) {
+ t << itemRow << endl;
+ }
+ }
+ }
+}
+
+void SymbianMakefileGenerator::writeBldInfContent(QTextStream &t, bool addDeploymentExtension, const QString &iconFile)
+{
+ // Read user defined bld inf rules
+
+ QMap<QString, QStringList> userBldInfRules;
+ for (QMap<QString, QStringList>::iterator it = project->variables().begin(); it != project->variables().end(); ++it) {
+ if (it.key().startsWith(BLD_INF_RULES_BASE)) {
+ QString newKey = it.key().mid(sizeof(BLD_INF_RULES_BASE) - 1);
+ if (newKey.isEmpty()) {
+ fprintf(stderr, "Warning: Empty BLD_INF_RULES key encountered\n");
+ continue;
+ }
+ QStringList newValues;
+ QStringList values = it.value();
+ foreach(QString item, values) {
+ // If there is no stringlist defined for a rule, use rule name directly
+ // This is convenience for defining single line statements
+ if (project->values(item).isEmpty()) {
+ newValues << item;
+ } else {
+ foreach(QString itemRow, project->values(item)) {
+ newValues << itemRow;
+ }
+ }
+ }
+ userBldInfRules.insert(newKey, newValues);
+ }
+ }
+
+ // Add includes of subdirs bld.inf files
+
+ QString currentPath = qmake_getpwd();
+ QDir directory(currentPath);
+
+ const QStringList &subdirs = project->values("SUBDIRS");
+ foreach(QString item, subdirs) {
+ bool fromFile = false;
+ QString fixedItem;
+ if (!project->isEmpty(item + ".file")) {
+ fixedItem = project->first(item + ".file");
+ fromFile = true;
+ } else if (!project->isEmpty(item + ".subdir")) {
+ fixedItem = project->first(item + ".subdir");
+ fromFile = false;
+ } else {
+ fixedItem = item;
+ fromFile = item.endsWith(Option::pro_ext);
+ }
+
+ QString condition;
+ if (!project->isEmpty(item + ".condition"))
+ condition = project->first(item + ".condition");
+
+ QFileInfo subdir(fileInfo(fixedItem));
+ QString relativePath = directory.relativeFilePath(fixedItem);
+ QString fullProName = subdir.absoluteFilePath();
+ QString bldinfFilename;
+ QString subdirFileName;
+
+ if (fromFile) {
+ subdirFileName = subdir.completeBaseName();
+ } else {
+ subdirFileName = subdir.fileName();
+ }
+
+ if (subdir.isDir()) {
+ // Subdir is a regular project
+ bldinfFilename = relativePath + QString("/") + QString(BLD_INF_FILENAME);
+ fullProName += QString("/") + subdirFileName + Option::pro_ext;
+ } else {
+ // Subdir is actually a .pro file
+ if (relativePath.contains("/")) {
+ // .pro not in same directory as parent .pro
+ relativePath.remove(relativePath.lastIndexOf("/") + 1, relativePath.length());
+ bldinfFilename = relativePath;
+ } else {
+ // .pro and parent .pro in same directory
+ bldinfFilename = QString("./");
+ }
+ bldinfFilename += QString(BLD_INF_FILENAME ".") + subdirFileName;
+ }
+
+ QString uid = generate_uid(fullProName);
+ QString bldinfDefine = QString("BLD_INF_") + subdirFileName + QString("_") + uid;
+ bldinfDefine = bldinfDefine.toUpper();
+
+ // replace anything not alphanumeric with underscore
+ QRegExp replacementMask(DEFINE_REPLACE_REGEXP);
+ bldinfDefine.replace(replacementMask, QLatin1String("_"));
+
+ if (!condition.isEmpty())
+ t << "#if defined(" << condition << ")" << endl;
+
+ t << "#ifndef " << bldinfDefine << endl;
+ t << "\t#include \"" << bldinfFilename << "\"" << endl;
+ t << "#endif" << endl;
+
+ if (!condition.isEmpty())
+ t << "#endif" << endl;
+
+ }
+
+ // Add supported project platforms
+
+ t << endl << BLD_INF_TAG_PLATFORMS << endl << endl;
+ if (0 != project->values("SYMBIAN_PLATFORMS").size())
+ t << project->values("SYMBIAN_PLATFORMS").join(" ") << endl;
+
+ QStringList userItems = userBldInfRules.value(BLD_INF_TAG_PLATFORMS);
+ foreach(QString item, userItems)
+ t << item << endl;
+ userBldInfRules.remove(BLD_INF_TAG_PLATFORMS);
+ t << endl;
+
+ // Add project mmps and old style extension makefiles
+
+ QString mmpTag;
+ if (project->isActiveConfig(SYMBIAN_TEST_CONFIG))
+ mmpTag = QLatin1String(BLD_INF_TAG_TESTMMPFILES);
+ else
+ mmpTag = QLatin1String(BLD_INF_TAG_MMPFILES);
+
+ t << endl << mmpTag << endl << endl;
+
+ writeBldInfMkFilePart(t, addDeploymentExtension);
+ if (targetType != TypeSubdirs)
+ t << mmpFileName << endl;
+
+ userItems = userBldInfRules.value(mmpTag);
+ foreach(QString item, userItems)
+ t << item << endl;
+ userBldInfRules.remove(mmpTag);
+
+ QString extensionTag;
+ if (project->isActiveConfig(SYMBIAN_TEST_CONFIG))
+ extensionTag = QLatin1String(BLD_INF_TAG_TESTEXTENSIONS);
+ else
+ extensionTag = QLatin1String(BLD_INF_TAG_EXTENSIONS);
+
+ t << endl << extensionTag << endl << endl;
+
+ // Generate extension rules
+
+ writeBldInfExtensionRulesPart(t, iconFile);
+
+ userItems = userBldInfRules.value(extensionTag);
+ foreach(QString item, userItems)
+ t << item << endl;
+ userBldInfRules.remove(extensionTag);
+
+ // Add rest of the user defined content
+
+ for (QMap<QString, QStringList>::iterator it = userBldInfRules.begin(); it != userBldInfRules.end(); ++it) {
+ t << endl << endl << it.key() << endl << endl;
+ userItems = it.value();
+ foreach(QString item, userItems)
+ t << item << endl;
+ }
+}
+
+void SymbianMakefileGenerator::appendIfnotExist(QStringList &list, QString value)
+{
+ if (!list.contains(value))
+ list += value;
+}
+
+void SymbianMakefileGenerator::appendIfnotExist(QStringList &list, QStringList values)
+{
+ foreach(QString item, values)
+ appendIfnotExist(list, item);
+}
+
+
+QString SymbianMakefileGenerator::removeTrailingPathSeparators(QString &file)
+{
+ QString ret = file;
+ if (ret.endsWith(QDir::separator())) {
+ ret.remove(ret.length() - 1, 1);
+ }
+
+ return ret;
+}
+
+void SymbianMakefileGenerator::generateCleanCommands(QTextStream& t,
+ const QStringList& toClean,
+ const QString& cmd,
+ const QString& cmdOptions,
+ const QString& itemPrefix,
+ const QString& itemSuffix)
+{
+ for (int i = 0; i < toClean.size(); ++i) {
+ QString item = toClean.at(i);
+ item.prepend(itemPrefix).append(itemSuffix);
+#if defined(Q_OS_WIN)
+ t << "\t-@ if EXIST \"" << QDir::toNativeSeparators(item) << "\" ";
+ t << cmd << " " << cmdOptions << " \"" << QDir::toNativeSeparators(item) << "\"" << endl;
+#else
+ t << "\t-if test -e " << QDir::toNativeSeparators(item) << "; then ";
+ t << cmd << " " << cmdOptions << " " << QDir::toNativeSeparators(item) << "; fi" << endl;
+#endif
+ }
+}
+
+void SymbianMakefileGenerator::generateDistcleanTargets(QTextStream& t)
+{
+ t << "dodistclean:" << endl;
+ const QStringList &subdirs = project->values("SUBDIRS");
+ foreach(QString item, subdirs) {
+ bool fromFile = false;
+ QString fixedItem;
+ if (!project->isEmpty(item + ".file")) {
+ fixedItem = project->first(item + ".file");
+ fromFile = true;
+ } else if (!project->isEmpty(item + ".subdir")) {
+ fixedItem = project->first(item + ".subdir");
+ fromFile = false;
+ } else {
+ fromFile = item.endsWith(Option::pro_ext);
+ fixedItem = item;
+ }
+ QFileInfo fi(fileInfo(fixedItem));
+ if (!fromFile) {
+ t << "\t-$(MAKE) -f \"" << Option::fixPathToTargetOS(fi.absoluteFilePath() + "/Makefile") << "\" dodistclean" << endl;
+ } else {
+ QString itemName = fi.fileName();
+ int extIndex = itemName.lastIndexOf(Option::pro_ext);
+ if (extIndex)
+ fixedItem = fi.absolutePath() + "/" + QString("Makefile.") + itemName.mid(0, extIndex);
+ t << "\t-$(MAKE) -f \"" << Option::fixPathToTargetOS(fixedItem) << "\" dodistclean" << endl;
+ }
+
+ }
+
+ generatedFiles << Option::fixPathToTargetOS(fileInfo(Option::output.fileName()).absoluteFilePath()); // bld.inf
+ generatedFiles << project->values("QMAKE_INTERNAL_PRL_FILE"); // Add generated prl files for cleanup
+ generatedFiles << project->values("QMAKE_DISTCLEAN"); // Add any additional files marked for distclean
+ QStringList fixedFiles;
+ QStringList fixedDirs;
+ foreach(QString item, generatedFiles) {
+ QString fixedItem = Option::fixPathToTargetOS(fileInfo(item).absoluteFilePath());
+ if (!fixedFiles.contains(fixedItem)) {
+ fixedFiles << fixedItem;
+ }
+ }
+ foreach(QString item, generatedDirs) {
+ QString fixedItem = Option::fixPathToTargetOS(fileInfo(item).absoluteFilePath());
+ if (!fixedDirs.contains(fixedItem)) {
+ fixedDirs << fixedItem;
+ }
+ }
+ generateCleanCommands(t, fixedFiles, "$(DEL_FILE)", "", "", "");
+ generateCleanCommands(t, fixedDirs, "$(DEL_DIR)", "", "", "");
+ t << endl;
+
+ t << "distclean: clean dodistclean" << endl;
+ t << endl;
+}
+
+// Returns a string that can be used as a dependency to loc file on other targets
+QString SymbianMakefileGenerator::generateLocFileTarget(QTextStream& t, const QString& locCmd)
+{
+ QString locFile;
+ if (targetType == TypeExe && !project->isActiveConfig("no_icon")) {
+ locFile = Option::fixPathToLocalOS(generateLocFileName());
+ t << locFile << QLatin1String(": ") << project->values("SYMBIAN_MATCHED_TRANSLATIONS").join(" ") << endl;
+ t << locCmd << endl;
+ t << endl;
+ locFile += QLatin1Char(' ');
+ }
+
+ return locFile;
+}
diff --git a/qmake/generators/symbian/symmake.h b/qmake/generators/symbian/symmake.h
new file mode 100644
index 0000000000..a38fbe54ed
--- /dev/null
+++ b/qmake/generators/symbian/symmake.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYMMAKEFILE_H
+#define SYMMAKEFILE_H
+
+#include "initprojectdeploy_symbian.h"
+#include "symbiancommon.h"
+#include <makefile.h>
+
+QT_BEGIN_NAMESPACE
+
+#define BLD_INF_FILENAME "bld.inf"
+#define MAKEFILE_DEPENDENCY_SEPARATOR " \\\n\t"
+#define QT_EXTRA_INCLUDE_DIR "tmp"
+#define MAKE_CACHE_NAME ".make.cache"
+#define SYMBIAN_TEST_CONFIG "symbian_test"
+
+class SymbianMakefileGenerator : public MakefileGenerator, public SymbianCommonGenerator
+{
+protected:
+ QString platform;
+ QString uid2;
+ QString mmpFileName;
+ QMap<QString, QStringList> sources;
+ QMap<QString, QStringList> systeminclude;
+ QMap<QString, QStringList> library;
+ // (output file) (source , command)
+ QMap<QString, QStringList> makmakeCommands;
+ QStringList overriddenMmpKeywords;
+
+ QString fixPathForMmp(const QString& origPath, const QDir& parentDir);
+ QString absolutizePath(const QString& origPath);
+
+ virtual bool writeMakefile(QTextStream &t);
+
+ virtual void init();
+
+ QString getTargetExtension();
+
+ QString generateUID3();
+
+ void initMmpVariables();
+ void generateMmpFileName();
+ void handleMmpRulesOverrides(QString &checkString,
+ bool &inResourceBlock,
+ QStringList &restrictedMmpKeywords,
+ const QStringList &restrictableMmpKeywords,
+ const QStringList &overridableMmpKeywords);
+ void appendKeywordIfMatchFound(QStringList &list,
+ const QStringList &keywordList,
+ QString &checkString);
+
+ void writeHeader(QTextStream &t);
+ void writeBldInfContent(QTextStream& t,
+ bool addDeploymentExtension,
+ const QString &iconFile);
+
+ static bool removeDuplicatedStrings(QStringList& stringList);
+
+ void writeMmpFileHeader(QTextStream &t);
+ void writeMmpFile(QString &filename, const SymbianLocalizationList &symbianLocalizationList);
+ void writeMmpFileMacrosPart(QTextStream& t);
+ void addMacro(QTextStream& t, const QString& value);
+ void writeMmpFileTargetPart(QTextStream& t);
+ void writeMmpFileResourcePart(QTextStream& t, const SymbianLocalizationList &symbianLocalizationList);
+ void writeMmpFileSystemIncludePart(QTextStream& t);
+ void writeMmpFileIncludePart(QTextStream& t);
+ void writeMmpFileLibraryPart(QTextStream& t);
+ void writeMmpFileCapabilityPart(QTextStream& t);
+ void writeMmpFileConditionalOptions(QTextStream& t,
+ const QString &optionType,
+ const QString &optionTag,
+ const QString &variableBase);
+ void writeMmpFileSimpleOption(QTextStream& t,
+ const QString &optionType,
+ const QString &optionTag,
+ const QString &options);
+ void appendMmpFileOptions(QString &options, const QStringList &list);
+ void writeMmpFileCompilerOptionPart(QTextStream& t);
+ void writeMmpFileBinaryVersionPart(QTextStream& t);
+ void writeMmpFileRulesPart(QTextStream& t);
+
+ void appendIfnotExist(QStringList &list, QString value);
+ void appendIfnotExist(QStringList &list, QStringList values);
+
+ QString removeTrailingPathSeparators(QString &file);
+ void generateCleanCommands(QTextStream& t,
+ const QStringList& toClean,
+ const QString& cmd,
+ const QString& cmdOptions,
+ const QString& itemPrefix,
+ const QString& itemSuffix);
+
+ void generateDistcleanTargets(QTextStream& t);
+ QString generateLocFileTarget(QTextStream& t, const QString& locCmd);
+
+ // Subclass implements
+ virtual void writeBldInfExtensionRulesPart(QTextStream& t, const QString &iconTargetFile) = 0;
+ virtual void writeBldInfMkFilePart(QTextStream& t, bool addDeploymentExtension) = 0;
+ virtual void writeMkFile(const QString& wrapperFileName, bool deploymentOnly) = 0;
+ virtual void writeWrapperMakefile(QFile& wrapperFile, bool isPrimaryMakefile) = 0;
+ virtual void appendAbldTempDirs(QStringList& sysincspaths, QString includepath) = 0;
+
+public:
+
+ SymbianMakefileGenerator();
+ ~SymbianMakefileGenerator();
+};
+
+#endif // SYMMAKEFILE_H
diff --git a/qmake/generators/symbian/symmake_abld.cpp b/qmake/generators/symbian/symmake_abld.cpp
new file mode 100644
index 0000000000..b582257519
--- /dev/null
+++ b/qmake/generators/symbian/symmake_abld.cpp
@@ -0,0 +1,523 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "symmake_abld.h"
+#include "initprojectdeploy_symbian.h"
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qdir.h>
+#include <qdatetime.h>
+#include <qdebug.h>
+
+// Included from tools/shared
+#include <symbian/epocroot_p.h>
+
+#define DO_NOTHING_TARGET "do_nothing"
+#define CREATE_TEMPS_TARGET "create_temps"
+#define EXTENSION_CLEAN "extension_clean"
+#define PRE_TARGETDEPS_TARGET "pre_targetdeps"
+#define COMPILER_CLEAN_TARGET "compiler_clean"
+#define FINALIZE_TARGET "finalize"
+#define GENERATED_SOURCES_TARGET "generated_sources"
+#define ALL_SOURCE_DEPS_TARGET "all_source_deps"
+#define DEPLOYMENT_TARGET "deployment"
+#define DEPLOYMENT_CLEAN_TARGET "deployment_clean"
+#define WINSCW_DEPLOYMENT_TARGET "winscw_deployment"
+#define WINSCW_DEPLOYMENT_CLEAN_TARGET "winscw_deployment_clean"
+#define STORE_BUILD_TARGET "store_build"
+
+SymbianAbldMakefileGenerator::SymbianAbldMakefileGenerator() : SymbianMakefileGenerator() { }
+SymbianAbldMakefileGenerator::~SymbianAbldMakefileGenerator() { }
+
+void SymbianAbldMakefileGenerator::writeMkFile(const QString& wrapperFileName, bool deploymentOnly)
+{
+ QFile ft(gnuMakefileName);
+ if (ft.open(QIODevice::WriteOnly)) {
+ generatedFiles << ft.fileName();
+ QTextStream t(&ft);
+
+ t << "# ==============================================================================" << endl;
+ t << "# Generated by qmake (" << qmake_version() << ") (Qt " << QT_VERSION_STR << ") on: ";
+ t << QDateTime::currentDateTime().toString() << endl;
+ t << "# This file is generated by qmake and should not be modified by the" << endl;
+ t << "# user." << endl;
+ t << "# Name : " << gnuMakefileName << endl;
+ t << "# Part of : " << project->values("TARGET").join(" ") << endl;
+ t << "# Description : This file is used to call necessary targets on wrapper makefile" << endl;
+ t << "# during normal Symbian build process." << endl;
+ t << "# Version : " << endl;
+ t << "#" << endl;
+ t << "# ==============================================================================" << "\n" << endl;
+
+ t << endl << endl;
+
+ t << "MAKE = make" << endl;
+ t << endl;
+
+ t << "VISUAL_CFG = RELEASE" << endl;
+ t << "ifeq \"$(CFG)\" \"UDEB\"" << endl;
+ t << "VISUAL_CFG = DEBUG" << endl;
+ t << "endif" << endl;
+ t << endl;
+
+ t << DO_NOTHING_TARGET " :" << endl;
+ t << "\t" << "@rem " DO_NOTHING_TARGET << endl << endl;
+
+ QString buildDeps;
+ QString cleanDeps;
+ QString finalDeps;
+ QString cleanDepsWinscw;
+ QString finalDepsWinscw;
+ QStringList wrapperTargets;
+ if (deploymentOnly) {
+ buildDeps.append(STORE_BUILD_TARGET);
+ cleanDeps.append(DEPLOYMENT_CLEAN_TARGET);
+ cleanDepsWinscw.append(WINSCW_DEPLOYMENT_CLEAN_TARGET " " DEPLOYMENT_CLEAN_TARGET);
+ finalDeps.append(DEPLOYMENT_TARGET);
+ finalDepsWinscw.append(WINSCW_DEPLOYMENT_TARGET " " DEPLOYMENT_TARGET);
+ wrapperTargets << WINSCW_DEPLOYMENT_TARGET
+ << WINSCW_DEPLOYMENT_CLEAN_TARGET
+ << DEPLOYMENT_TARGET
+ << DEPLOYMENT_CLEAN_TARGET
+ << STORE_BUILD_TARGET;
+ } else {
+ buildDeps.append(CREATE_TEMPS_TARGET " " PRE_TARGETDEPS_TARGET " " STORE_BUILD_TARGET);
+ cleanDeps.append(EXTENSION_CLEAN " " DEPLOYMENT_CLEAN_TARGET);
+ cleanDepsWinscw.append(EXTENSION_CLEAN " " WINSCW_DEPLOYMENT_CLEAN_TARGET " " DEPLOYMENT_CLEAN_TARGET);
+ finalDeps.append(FINALIZE_TARGET " " DEPLOYMENT_TARGET);
+ finalDepsWinscw.append(FINALIZE_TARGET " " WINSCW_DEPLOYMENT_TARGET " " DEPLOYMENT_TARGET);
+ wrapperTargets << PRE_TARGETDEPS_TARGET
+ << CREATE_TEMPS_TARGET
+ << EXTENSION_CLEAN
+ << FINALIZE_TARGET
+ << WINSCW_DEPLOYMENT_CLEAN_TARGET
+ << WINSCW_DEPLOYMENT_TARGET
+ << DEPLOYMENT_CLEAN_TARGET
+ << DEPLOYMENT_TARGET
+ << STORE_BUILD_TARGET;
+ }
+
+ t << "MAKMAKE: " << buildDeps << endl << endl;
+ t << "LIB: " << buildDeps << endl << endl;
+ t << "BLD: " << buildDeps << endl << endl;
+ t << "ifeq \"$(PLATFORM)\" \"WINSCW\"" << endl;
+ t << "CLEAN: " << cleanDepsWinscw << endl;
+ t << "else" << endl;
+ t << "CLEAN: " << cleanDeps << endl;
+ t << "endif" << endl << endl;
+ t << "CLEANLIB: " DO_NOTHING_TARGET << endl << endl;
+ t << "RESOURCE: " DO_NOTHING_TARGET << endl << endl;
+ t << "FREEZE: " DO_NOTHING_TARGET << endl << endl;
+ t << "SAVESPACE: " DO_NOTHING_TARGET << endl << endl;
+ t << "RELEASABLES: " DO_NOTHING_TARGET << endl << endl;
+ t << "ifeq \"$(PLATFORM)\" \"WINSCW\"" << endl;
+ t << "FINAL: " << finalDepsWinscw << endl;
+ t << "else" << endl;
+ t << "FINAL: " << finalDeps << endl;
+ t << "endif" << endl << endl;
+
+ QString makefile(Option::fixPathToTargetOS(fileInfo(wrapperFileName).canonicalFilePath()));
+ foreach(QString target, wrapperTargets) {
+ t << target << " : " << makefile << endl;
+ t << "\t-$(MAKE) -f \"" << makefile << "\" " << target << " QT_SIS_TARGET=$(VISUAL_CFG)-$(PLATFORM)" << endl << endl;
+ }
+
+ t << endl;
+ } // if(ft.open(QIODevice::WriteOnly))
+}
+
+void SymbianAbldMakefileGenerator::writeWrapperMakefile(QFile& wrapperFile, bool isPrimaryMakefile)
+{
+ QStringList allPlatforms;
+ foreach(QString platform, project->values("SYMBIAN_PLATFORMS")) {
+ allPlatforms << platform.toLower();
+ }
+
+ QStringList debugPlatforms = allPlatforms;
+ QStringList releasePlatforms = allPlatforms;
+ releasePlatforms.removeAll("winscw"); // No release for emulator
+
+ QString testClause;
+ if (project->isActiveConfig(SYMBIAN_TEST_CONFIG))
+ testClause = QLatin1String(" test");
+ else
+ testClause = QLatin1String("");
+
+ QTextStream t(&wrapperFile);
+
+ MakefileGenerator::writeHeader(t);
+
+ t << "MAKEFILE = " << fileInfo(wrapperFile.fileName()).fileName() << endl;
+ t << "QMAKE = " << var("QMAKE_QMAKE") << endl;
+ t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ t << "DEL_DIR = " << var("QMAKE_DEL_DIR") << endl;
+ t << "DEL_TREE = " << var("QMAKE_DEL_TREE") << endl;
+ t << "MOVE = " << var("QMAKE_MOVE") << endl;
+ t << "CHK_DIR_EXISTS = " << var("QMAKE_CHK_DIR_EXISTS") << endl;
+ t << "MKDIR = " << var("QMAKE_MKDIR") << endl;
+#ifdef Q_OS_WIN32
+ t << "XCOPY = xcopy /d /f /h /r /y /i" << endl;
+ t << "ABLD = ABLD.BAT" << endl;
+#elif defined(Q_OS_MAC)
+ t << "XCOPY = cp -R -v" << endl;
+ t << "ABLD = abld" << endl;
+#else
+ t << "XCOPY = cp -R -u -v" << endl;
+ t << "ABLD = abld" << endl;
+#endif
+ t << "DEBUG_PLATFORMS = " << debugPlatforms.join(" ") << endl;
+ t << "RELEASE_PLATFORMS = " << releasePlatforms.join(" ") << endl;
+ t << "MAKE = make" << endl;
+ t << endl;
+ t << "ifeq (WINS,$(findstring WINS, $(PLATFORM)))" << endl;
+ t << "ZDIR=$(EPOCROOT)" << QDir::toNativeSeparators("epoc32/release/$(PLATFORM)/$(CFG)/z") << endl;
+ t << "else" << endl;
+ t << "ZDIR=$(EPOCROOT)" << QDir::toNativeSeparators("epoc32/data/z") << endl;
+ t << "endif" << endl;
+ t << endl;
+ t << "DEFINES" << '\t' << " = "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << varGlue("QMAKE_COMPILER_DEFINES", "-D", "-D", " ")
+ << varGlue("DEFINES","-D"," -D","") << endl;
+
+ t << "INCPATH" << '\t' << " = ";
+
+ for (QMap<QString, QStringList>::iterator it = systeminclude.begin(); it != systeminclude.end(); ++it) {
+ QStringList values = it.value();
+ for (int i = 0; i < values.size(); ++i) {
+ t << " -I\"" << values.at(i) << "\"";
+ }
+ }
+ t << endl;
+ t << "first: default" << endl;
+ if (debugPlatforms.contains("winscw"))
+ t << "default: debug-winscw";
+ else if (debugPlatforms.contains("armv5"))
+ t << "default: debug-armv5";
+ else if (debugPlatforms.size())
+ t << "default: debug-" << debugPlatforms.first();
+ else
+ t << "default: all";
+
+ t << endl;
+ if (!isPrimaryMakefile) {
+ t << "all:" << endl;
+ } else {
+ t << "all: debug release" << endl;
+ t << endl;
+
+ QString qmakeCmd = "\t$(QMAKE) \"" + project->projectFile() + "\" " + buildArgs();
+
+ t << "qmake:" << endl;
+ t << qmakeCmd << endl;
+ t << endl;
+
+ t << BLD_INF_FILENAME ": " << project->projectFile() << endl;
+ t << qmakeCmd << endl;
+ t << endl;
+
+ t << "$(ABLD): " BLD_INF_FILENAME << endl;
+ t << "\tbldmake bldfiles" << endl;
+ t << endl;
+
+ QString locFileDep = generateLocFileTarget(t, qmakeCmd);
+
+ t << "debug: " << locFileDep << "$(ABLD)" << endl;
+ foreach(QString item, debugPlatforms) {
+ t << "\t$(ABLD)" << testClause << " build " << item << " udeb" << endl;
+ }
+ t << endl;
+ t << "release: " << locFileDep << "$(ABLD)" << endl;
+ foreach(QString item, releasePlatforms) {
+ t << "\t$(ABLD)" << testClause << " build " << item << " urel" << endl;
+ }
+ t << endl;
+
+ // For more specific builds, targets are in this form: build-platform, e.g. release-armv5
+ foreach(QString item, debugPlatforms) {
+ t << "debug-" << item << ": " << locFileDep << "$(ABLD)" << endl;
+ t << "\t$(ABLD)" << testClause << " build " << item << " udeb" << endl;
+ }
+
+ foreach(QString item, releasePlatforms) {
+ t << "release-" << item << ": " << locFileDep << "$(ABLD)" << endl;
+ t << "\t$(ABLD)" << testClause << " build " << item << " urel" << endl;
+ }
+
+ t << endl;
+ t << "export: $(ABLD)" << endl;
+ t << "\t$(ABLD)" << testClause << " export" << endl;
+ t << endl;
+
+ t << "cleanexport: $(ABLD)" << endl;
+ t << "\t$(ABLD)" << testClause << " cleanexport" << endl;
+ t << endl;
+
+ }
+
+ // pre_targetdeps target depends on:
+ // - all targets specified in PRE_TARGETDEPS
+ // - the GENERATED_SOURCES sources (so that they get generated)
+ // - all dependencies of sources targeted for compilation
+ // (mainly to ensure that any included UNUSED_SOURCES that need to be generated get generated)
+ //
+ // Unfortunately, Symbian build chain doesn't support linking generated objects to target,
+ // so supporting generating sources is the best we can do. This is enough for mocs.
+
+ if (targetType != TypeSubdirs) {
+ writeExtraTargets(t);
+ writeExtraCompilerTargets(t);
+
+ t << CREATE_TEMPS_TARGET ":" << endl;
+ // generate command lines like this ...
+ // -@ if NOT EXIST ".\somedir" mkdir ".\somedir"
+ QStringList dirsToClean;
+ QString dirExists = var("QMAKE_CHK_DIR_EXISTS");
+ QString mkdir = var("QMAKE_MKDIR");
+ for (QMap<QString, QStringList>::iterator it = systeminclude.begin(); it != systeminclude.end(); ++it) {
+ QStringList values = it.value();
+ for (int i = 0; i < values.size(); ++i) {
+ if (values.at(i).endsWith("/" QT_EXTRA_INCLUDE_DIR)) {
+ QString fixedValue(QDir::toNativeSeparators(values.at(i)));
+ dirsToClean << fixedValue;
+ t << "\t-@ " << dirExists << " \"" << fixedValue << "\" "
+ << (isWindowsShell() ? "" : "|| ")
+ << mkdir << " \"" << fixedValue << "\"" << endl;
+ }
+ }
+ }
+ t << endl;
+
+ // Note: EXTENSION_CLEAN will get called many times when doing reallyclean
+ // This is why the "2> NUL" gets appended to generated clean targets in makefile.cpp.
+ t << EXTENSION_CLEAN ": " COMPILER_CLEAN_TARGET << endl;
+ generateCleanCommands(t, dirsToClean, "$(DEL_TREE)", "", "", "");
+ generateCleanCommands(t, project->values("QMAKE_CLEAN"), "$(DEL_FILE)", "", "", "");
+ t << endl;
+
+ t << PRE_TARGETDEPS_TARGET ":"
+ << MAKEFILE_DEPENDENCY_SEPARATOR GENERATED_SOURCES_TARGET
+ << MAKEFILE_DEPENDENCY_SEPARATOR ALL_SOURCE_DEPS_TARGET;
+ if (project->values("PRE_TARGETDEPS").size())
+ t << MAKEFILE_DEPENDENCY_SEPARATOR << project->values("PRE_TARGETDEPS").join(MAKEFILE_DEPENDENCY_SEPARATOR);
+ t << endl << endl;
+ t << GENERATED_SOURCES_TARGET ":";
+ if (project->values("GENERATED_SOURCES").size())
+ t << MAKEFILE_DEPENDENCY_SEPARATOR << project->values("GENERATED_SOURCES").join(MAKEFILE_DEPENDENCY_SEPARATOR);
+ t << endl << endl;
+ t << ALL_SOURCE_DEPS_TARGET ":";
+
+ QStringList allDeps;
+ for (QMap<QString, QStringList>::iterator it = sources.begin(); it != sources.end(); ++it) {
+ QString currentSourcePath = it.key();
+ QStringList values = it.value();
+ for (int i = 0; i < values.size(); ++i) {
+ // we need additional check
+ QString sourceFile = currentSourcePath + "/" + values.at(i);
+ QStringList deps = findDependencies(QDir::toNativeSeparators(sourceFile));
+ appendIfnotExist(allDeps, deps);
+ }
+ }
+
+ foreach(QString item, allDeps) {
+ t << MAKEFILE_DEPENDENCY_SEPARATOR << item;
+ }
+ t << endl << endl;
+
+ // Post link operations
+ t << FINALIZE_TARGET ":" << endl;
+ if (!project->isEmpty("QMAKE_POST_LINK")) {
+ t << '\t' << var("QMAKE_POST_LINK");
+ t << endl;
+ }
+ t << endl;
+ } else {
+ QList<MakefileGenerator::SubTarget*> subtargets = findSubDirsSubTargets();
+ writeSubTargets(t, subtargets, SubTargetSkipDefaultVariables | SubTargetSkipDefaultTargets);
+ qDeleteAll(subtargets);
+ }
+
+ // Deploymend targets for both emulator and rom deployment
+ writeDeploymentTargets(t, false);
+ writeDeploymentTargets(t, true);
+
+ generateDistcleanTargets(t);
+
+ t << "clean: $(ABLD)" << endl;
+ t << "\t-$(ABLD)" << testClause << " reallyclean" << endl;
+ t << "\t-bldmake clean" << endl;
+ t << endl;
+
+ t << "clean-debug: $(ABLD)" << endl;
+ foreach(QString item, debugPlatforms) {
+ t << "\t$(ABLD)" << testClause << " reallyclean " << item << " udeb" << endl;
+ }
+ t << endl;
+ t << "clean-release: $(ABLD)" << endl;
+ foreach(QString item, releasePlatforms) {
+ t << "\t$(ABLD)" << testClause << " reallyclean " << item << " urel" << endl;
+ }
+ t << endl;
+
+ // For more specific builds, targets are in this form: clean-build-platform, e.g. clean-release-armv5
+ foreach(QString item, debugPlatforms) {
+ t << "clean-debug-" << item << ": $(ABLD)" << endl;
+ t << "\t$(ABLD)" << testClause << " reallyclean " << item << " udeb" << endl;
+ }
+ foreach(QString item, releasePlatforms) {
+ t << "clean-release-" << item << ": $(ABLD)" << endl;
+ t << "\t$(ABLD)" << testClause << " reallyclean " << item << " urel" << endl;
+ }
+ t << endl;
+
+ t << "freeze: $(ABLD)" << endl;
+ t << "\t$(ABLD)" << testClause << " freeze" << endl;
+ t << endl;
+
+ // Abld toolchain doesn't differentiate between freezing release or debug
+ t << "freeze-debug: freeze" << endl << endl;
+ t << "freeze-release: freeze" << endl << endl;
+
+ // For more specific builds, targets are in this form: freeze-build-platform, e.g. freeze-release-armv5,
+ // though note that debug and release targets of each platform are identical in symbian-abld.
+ foreach(QString item, debugPlatforms) {
+ t << "freeze-debug-" << item << ": $(ABLD)" << endl;
+ t << "\t$(ABLD)" << testClause << " freeze " << item << endl;
+ }
+ foreach(QString item, releasePlatforms) {
+ t << "freeze-release-" << item << ": $(ABLD)" << endl;
+ t << "\t$(ABLD)" << testClause << " freeze " << item << endl;
+ }
+
+ t << endl;
+}
+
+void SymbianAbldMakefileGenerator::writeBldInfExtensionRulesPart(QTextStream& t, const QString &iconTargetFile)
+{
+ // We don't use extensions for anything in abld
+ Q_UNUSED(t);
+ Q_UNUSED(iconTargetFile);
+}
+
+bool SymbianAbldMakefileGenerator::writeDeploymentTargets(QTextStream &t, bool isRom)
+{
+ if (isRom)
+ t << DEPLOYMENT_TARGET ":" << endl;
+ else
+ t << WINSCW_DEPLOYMENT_TARGET ":" << endl;
+
+ QString remoteTestPath = qt_epocRoot()
+ + QDir::toNativeSeparators(QLatin1String(isRom ? "epoc32/data/z/private/"
+ : "epoc32/winscw/c/private/"))
+ + privateDirUid;
+ DeploymentList depList;
+
+ initProjectDeploySymbian(project, depList, remoteTestPath, false, true,
+ QLatin1String(isRom ? ROM_DEPLOYMENT_PLATFORM : EMULATOR_DEPLOYMENT_PLATFORM),
+ QString(), generatedDirs, generatedFiles);
+
+ if (depList.size())
+ t << "\t-echo Deploying changed files..." << endl;
+
+ for (int i = 0; i < depList.size(); ++i) {
+#ifdef Q_OS_WIN32
+ // Xcopy prompts for selecting file or directory if target doesn't exist,
+ // and doesn't provide switch to force file selection. It does provide dir forcing, though,
+ // so strip the last part of the destination.
+ t << "\t-$(XCOPY) \"" << depList.at(i).from << "\" \""
+ << depList.at(i).to.left(depList.at(i).to.lastIndexOf("\\") + 1) << "\"" << endl;
+#else
+ QString dirExists = var("QMAKE_CHK_DIR_EXISTS");
+ QString mkdir = var("QMAKE_MKDIR");
+ QString dir = QFileInfo(depList.at(i).to).dir().path();
+ t << "\t-@ " << dirExists << " \"" << dir << "\" || "
+ << mkdir << " \"" << dir << "\"" << endl;
+ t << "\t-$(XCOPY) \"" << QDir::toNativeSeparators(depList.at(i).from) << "\" \""
+ << QDir::toNativeSeparators(depList.at(i).to) << "\"" << endl;
+#endif
+ }
+
+ t << endl;
+
+ if (isRom)
+ t << DEPLOYMENT_CLEAN_TARGET ":" << endl;
+ else
+ t << WINSCW_DEPLOYMENT_CLEAN_TARGET ":" << endl;
+
+ QStringList cleanList;
+ for (int i = 0; i < depList.size(); ++i) {
+ cleanList.append(QDir::toNativeSeparators(depList.at(i).to));
+ }
+ generateCleanCommands(t, cleanList, "$(DEL_FILE)", "", "", "");
+
+ // Note: If deployment creates any directories, they will not get deleted after cleanup.
+ // To do this in robust fashion could be quite complex.
+
+ t << endl;
+
+ return true;
+}
+
+void SymbianAbldMakefileGenerator::writeBldInfMkFilePart(QTextStream& t, bool addDeploymentExtension)
+{
+ // Normally emulator deployment gets done via regular makefile, but since subdirs
+ // do not get that, special deployment only makefile is generated for them if needed.
+ if (targetType != TypeSubdirs || addDeploymentExtension) {
+ gnuMakefileName = QLatin1String("Makefile_") + fileInfo(mmpFileName).completeBaseName()
+ + QLatin1String(".mk");
+ t << "gnumakefile " << gnuMakefileName << endl;
+ }
+}
+
+void SymbianAbldMakefileGenerator::appendAbldTempDirs(QStringList& sysincspaths, QString includepath)
+{
+ // As a workaround for Symbian toolchain insistence to treat include
+ // statements as relative to source file rather than the file they appear in,
+ // we generate extra temporary include directories to make
+ // relative include paths used in various headers to work properly.
+ // Note that this is not a fix-all solution; it's just a stop-gap measure
+ // to make Qt itself build until toolchain can support relative includes in
+ // a way that Qt expects.
+ QString epocPath("epoc32");
+ if (!includepath.contains(epocPath)) // No temp dirs for epoc includes
+ appendIfnotExist(sysincspaths, includepath + QString("/" QT_EXTRA_INCLUDE_DIR));
+}
diff --git a/qmake/generators/symbian/symmake_abld.h b/qmake/generators/symbian/symmake_abld.h
new file mode 100644
index 0000000000..3ac27b0ccc
--- /dev/null
+++ b/qmake/generators/symbian/symmake_abld.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYMMAKE_ABLD_H
+#define SYMMAKE_ABLD_H
+
+#include <symmake.h>
+
+QT_BEGIN_NAMESPACE
+
+class SymbianAbldMakefileGenerator : public SymbianMakefileGenerator
+{
+protected:
+
+ // Inherited from parent
+ virtual void writeBldInfExtensionRulesPart(QTextStream& t, const QString &iconTargetFile);
+ virtual void writeBldInfMkFilePart(QTextStream& t, bool addDeploymentExtension);
+ virtual void writeMkFile(const QString& wrapperFileName, bool deploymentOnly);
+ virtual void writeWrapperMakefile(QFile& wrapperFile, bool isPrimaryMakefile);
+ virtual void appendAbldTempDirs(QStringList& sysincspaths, QString includepath);
+
+ bool writeDeploymentTargets(QTextStream &t, bool isRom);
+ QString gnuMakefileName;
+public:
+
+ SymbianAbldMakefileGenerator();
+ ~SymbianAbldMakefileGenerator();
+};
+
+#endif // SYMMAKE_ABLD_H
diff --git a/qmake/generators/symbian/symmake_sbsv2.cpp b/qmake/generators/symbian/symmake_sbsv2.cpp
new file mode 100644
index 0000000000..767645ac2d
--- /dev/null
+++ b/qmake/generators/symbian/symmake_sbsv2.cpp
@@ -0,0 +1,760 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "symmake_sbsv2.h"
+#include "initprojectdeploy_symbian.h"
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qdir.h>
+#include <qdatetime.h>
+#include <qdebug.h>
+
+// Included from tools/shared
+#include <symbian/epocroot_p.h>
+
+SymbianSbsv2MakefileGenerator::SymbianSbsv2MakefileGenerator() : SymbianMakefileGenerator() { }
+SymbianSbsv2MakefileGenerator::~SymbianSbsv2MakefileGenerator() { }
+
+#define FLM_DEST_DIR "epoc32/tools/makefile_templates/qt"
+#define FLM_SOURCE_DIR "/mkspecs/symbian-sbsv2/flm/qt"
+#define PLATFORM_GCCE "gcce"
+#define PLATFORM_WINSCW "winscw"
+#define PLATFORM_ARM_PREFIX "arm"
+#define BUILD_DEBUG "udeb"
+#define BUILD_RELEASE "urel"
+#define SBS_RVCT_PREFIX "rvct"
+
+static QString winscwPlatform;
+static QString armPlatformPrefix;
+static QString gccePlatform;
+static QString sbsRvctPrefix;
+
+#if defined(Q_OS_UNIX)
+ extern char **environ;
+#endif
+
+static void fixFlmCmd(QString *cmdLine, const QMap<QString, QString> &commandsToReplace)
+{
+ // If commandItem starts with any $$QMAKE_* commands, do a replace for SBS equivalent.
+ // Command replacement is done only for the start of the command or right after
+ // concatenation operators (&& and ||), as otherwise unwanted replacements might occur.
+ static QString cmdFind(QLatin1String("(^|&&\\s*|\\|\\|\\s*)%1"));
+ static QString cmdReplace(QLatin1String("\\1%1"));
+
+ // $$escape_expand(\\n\\t) doesn't work for bld.inf files, but is often used as command
+ // separator, so replace it with "&&" command concatenator.
+ cmdLine->replace("\n\t", "&&");
+
+ // Strip output suppression, as sbsv2 can't handle it in FLMs. Cannot be done by simply
+ // adding "@" to commandsToReplace, as it'd get handled last due to alphabetical ordering,
+ // potentially masking other commands that need replacing.
+ if (cmdLine->contains("@"))
+ cmdLine->replace(QRegExp(cmdFind.arg("@")), cmdReplace.arg(""));
+
+ // Iterate command replacements in reverse alphabetical order of keys so
+ // that keys which are starts of other longer keys are iterated after longer keys.
+ QMapIterator<QString, QString> cmdIter(commandsToReplace);
+ cmdIter.toBack();
+ while (cmdIter.hasPrevious()) {
+ cmdIter.previous();
+ if (cmdLine->contains(cmdIter.key()))
+ cmdLine->replace(QRegExp(cmdFind.arg(cmdIter.key())), cmdReplace.arg(cmdIter.value()));
+ }
+
+ // Sbsv2 toolchain strips all backslashes (even double ones) from option parameters, so just
+ // assume all backslashes are directory separators and replace them with slashes.
+ // Problem: If some command actually needs backslashes for something else than dir separator,
+ // we are out of luck.
+ cmdLine->replace("\\", "/");
+}
+
+// Copies Qt FLMs to correct location under epocroot.
+// This is not done by configure as it is possible to change epocroot after configure.
+void SymbianSbsv2MakefileGenerator::exportFlm()
+{
+ static bool flmExportDone = false;
+
+ if (!flmExportDone) {
+ QDir sourceDir = QDir(QLibraryInfo::location(QLibraryInfo::PrefixPath) + FLM_SOURCE_DIR);
+ QFileInfoList sourceInfos = sourceDir.entryInfoList(QDir::Files);
+
+ QDir destDir(qt_epocRoot() + FLM_DEST_DIR);
+ if (!destDir.exists()) {
+ if (destDir.mkpath(destDir.absolutePath()))
+ generatedDirs << destDir.absolutePath();
+ }
+
+ foreach(QFileInfo item, sourceInfos) {
+ QFileInfo destInfo = QFileInfo(destDir.absolutePath() + "/" + item.fileName());
+ if (!destInfo.exists() || destInfo.lastModified() != item.lastModified()) {
+ if (destInfo.exists())
+ QFile::remove(destInfo.absoluteFilePath());
+ if (QFile::copy(item.absoluteFilePath(), destInfo.absoluteFilePath()))
+ generatedFiles << destInfo.absoluteFilePath();
+ else
+ fprintf(stderr, "Error: Could not copy '%s' -> '%s'\n",
+ qPrintable(item.absoluteFilePath()),
+ qPrintable(destInfo.absoluteFilePath()));
+ }
+ }
+ flmExportDone = true;
+ }
+}
+
+void SymbianSbsv2MakefileGenerator::findInstalledCompilerVersions(const QString &matchExpression,
+ const QString &versionPrefix,
+ QStringList *versionList)
+{
+ // No need to be able to find env variables on other operating systems,
+ // as only linux and windows have support for symbian-sbsv2 toolchain
+#if defined(Q_OS_UNIX) || defined(Q_OS_WIN)
+ char *entry = 0;
+ int count = 0;
+ QRegExp matcher(matchExpression);
+ while ((entry = environ[count++])) {
+ if (matcher.exactMatch(QString::fromLocal8Bit(entry))
+ && fileInfo(matcher.cap(matcher.captureCount())).exists()) {
+ // First capture (index 0) is the whole match, which is skipped.
+ // Next n captures are version numbers, which are interesting.
+ // Final capture is the env var value, which we already used, so that is skipped, too.
+ int capture = 1;
+ int finalCapture = matcher.captureCount() - 1;
+ QString version = versionPrefix;
+ while (capture <= finalCapture) {
+ version.append(matcher.cap(capture));
+ if (capture != finalCapture)
+ version.append(QLatin1Char('.'));
+ capture++;
+ }
+ *versionList << version;
+ }
+ }
+#endif
+}
+
+void SymbianSbsv2MakefileGenerator::findGcceVersions(QStringList *gcceVersionList,
+ QString *defaultVersion)
+{
+ QString matchStr = QLatin1String("SBS_GCCE(\\d)(\\d)(\\d)BIN=(.*)");
+ findInstalledCompilerVersions(matchStr, gccePlatform, gcceVersionList);
+
+ QString qtGcceVersion = QString::fromLocal8Bit(qgetenv("QT_GCCE_VERSION"));
+
+ if (!qtGcceVersion.isEmpty()) {
+ if (QRegExp("\\d+\\.\\d+\\.\\d+").exactMatch(qtGcceVersion)) {
+ *defaultVersion = gccePlatform + qtGcceVersion;
+ } else {
+ fprintf(stderr, "Warning: Variable QT_GCCE_VERSION ('%s') is in incorrect "
+ "format, expected format is: 'x.y.z'. Attempting to autodetect GCCE version.\n",
+ qPrintable(qtGcceVersion));
+ }
+ }
+
+ if (defaultVersion->isEmpty() && gcceVersionList->size()) {
+ gcceVersionList->sort();
+ *defaultVersion = gcceVersionList->last();
+ }
+}
+
+void SymbianSbsv2MakefileGenerator::findRvctVersions(QStringList *rvctVersionList,
+ QString *defaultVersion)
+{
+ QString matchStr = QLatin1String("RVCT(\\d)(\\d)BIN=(.*)");
+ findInstalledCompilerVersions(matchStr, sbsRvctPrefix, rvctVersionList);
+
+ QString qtRvctVersion = QString::fromLocal8Bit(qgetenv("QT_RVCT_VERSION"));
+
+ if (!qtRvctVersion.isEmpty()) {
+ if (QRegExp("\\d+\\.\\d+").exactMatch(qtRvctVersion)) {
+ *defaultVersion = sbsRvctPrefix + qtRvctVersion;
+ } else {
+ fprintf(stderr, "Warning: Variable QT_RVCT_VERSION ('%s') is in incorrect "
+ "format, expected format is: 'x.y'.\n",
+ qPrintable(qtRvctVersion));
+ }
+ }
+}
+
+QString SymbianSbsv2MakefileGenerator::configClause(const QString &platform,
+ const QString &build,
+ const QString &compilerVersion,
+ const QString &clauseTemplate)
+{
+ QString retval;
+ if (QString::compare(platform, winscwPlatform) == 0) {
+ retval = clauseTemplate.arg(build);
+ } else if (platform.startsWith(armPlatformPrefix)) {
+ QString fixedCompilerVersion = compilerVersion;
+ fixedCompilerVersion.replace(".","_");
+ retval = clauseTemplate.arg(platform.mid(sizeof(PLATFORM_ARM_PREFIX)-1))
+ .arg(build)
+ .arg(fixedCompilerVersion);
+ } // else - Unsupported platform for makefile target, return empty clause
+ return retval;
+}
+
+void SymbianSbsv2MakefileGenerator::writeSbsDeploymentList(const DeploymentList& depList, QTextStream& t)
+{
+ for (int i = 0; i < depList.size(); ++i) {
+ t << "START EXTENSION qt/qmake_emulator_deployment" << endl;
+ QString fromItem = depList.at(i).from;
+ QString toItem = depList.at(i).to;
+ fromItem.replace("\\", "/");
+ toItem.replace("\\", "/");
+#if defined(Q_OS_WIN)
+ // add drive if it doesn't have one yet
+ if (toItem.size() > 1 && toItem[1] != QLatin1Char(':'))
+ toItem.prepend(QDir::current().absolutePath().left(2));
+#endif
+ t << "OPTION DEPLOY_SOURCE " << fromItem << endl;
+ t << "OPTION DEPLOY_TARGET " << toItem << endl;
+ t << "END" << endl;
+ }
+}
+
+void SymbianSbsv2MakefileGenerator::writeMkFile(const QString& wrapperFileName, bool deploymentOnly)
+{
+ // Can't use extension makefile with sbsv2
+ Q_UNUSED(wrapperFileName);
+ Q_UNUSED(deploymentOnly);
+}
+
+void SymbianSbsv2MakefileGenerator::writeWrapperMakefile(QFile& wrapperFile, bool isPrimaryMakefile)
+{
+ static QString debugBuild;
+ static QString releaseBuild;
+ static QString defaultGcceCompilerVersion;
+ static QString defaultRvctCompilerVersion;
+ static QStringList rvctVersions;
+ static QStringList gcceVersions;
+ static QStringList allArmCompilerVersions;
+
+ // Initialize static variables used in makefile creation
+ if (debugBuild.isEmpty()) {
+ debugBuild.append(QLatin1String(BUILD_DEBUG));
+ releaseBuild.append(QLatin1String(BUILD_RELEASE));
+ winscwPlatform.append(QLatin1String(PLATFORM_WINSCW));
+ gccePlatform.append(QLatin1String(PLATFORM_GCCE));
+ armPlatformPrefix.append(QLatin1String(PLATFORM_ARM_PREFIX));
+ sbsRvctPrefix.append(QLatin1String(SBS_RVCT_PREFIX));
+
+ findGcceVersions(&gcceVersions, &defaultGcceCompilerVersion);
+ findRvctVersions(&rvctVersions, &defaultRvctCompilerVersion);
+
+ allArmCompilerVersions << rvctVersions << gcceVersions;
+
+ if (!allArmCompilerVersions.size()) {
+ fprintf(stderr, "Warning: No HW compilers detected. "
+ "Please install either GCCE or RVCT compiler to enable release builds.\n");
+ }
+ }
+
+ QStringList allPlatforms;
+ foreach(QString platform, project->values("SYMBIAN_PLATFORMS")) {
+ allPlatforms << platform.toLower();
+ }
+
+ if (!gcceVersions.size())
+ allPlatforms.removeAll(gccePlatform);
+
+ QString testClause;
+ if (project->isActiveConfig(SYMBIAN_TEST_CONFIG))
+ testClause = QLatin1String(".test");
+ else
+ testClause = QLatin1String("");
+
+ // Note: armClause is used for gcce, too, which has a side effect
+ // of requiring armv* platform(s) in SYMBIAN_PLATFORMS in order
+ // to get any compiler version specific targets.
+ QString armClause = " -c " PLATFORM_ARM_PREFIX ".%1.%2.%3" + testClause;
+ QString genericArmClause;
+ if (defaultRvctCompilerVersion.isEmpty()) {
+ // Note: Argument %3 needs to be empty string in this version of clause
+ genericArmClause = " -c " PLATFORM_ARM_PREFIX "%1_%2%3" + testClause;
+ } else {
+ // If defaultRvctCompilerVersion is defined, use specific sbs clause for "generic" clause
+ genericArmClause = armClause;
+ }
+ QString winscwClause = " -c " PLATFORM_WINSCW "_%1.mwccinc" + testClause;;
+
+ QStringList armPlatforms = allPlatforms.filter(QRegExp("^" PLATFORM_ARM_PREFIX));
+
+ if (!allArmCompilerVersions.size()) {
+ foreach (QString item, armPlatforms) {
+ allPlatforms.removeAll(item);
+ }
+ armPlatforms.clear();
+ }
+
+ QStringList allClauses;
+ QStringList debugClauses;
+ QStringList releaseClauses;
+
+ // Only winscw and arm platforms are supported
+ QStringList debugPlatforms = allPlatforms;
+ QStringList releasePlatforms = allPlatforms;
+ releasePlatforms.removeAll(winscwPlatform); // No release for emulator
+
+ if (!releasePlatforms.size()) {
+ fprintf(stderr, "Warning: No valid release platforms in SYMBIAN_PLATFORMS (%s)\n"
+ "Most likely required compiler(s) are not properly installed.\n",
+ qPrintable(project->values("SYMBIAN_PLATFORMS").join(" ")));
+ }
+
+ if (debugPlatforms.contains(winscwPlatform))
+ debugClauses << configClause(winscwPlatform, debugBuild, QString(), winscwClause);
+
+ foreach(QString item, armPlatforms) {
+ // Only use single clause per arm platform even if multiple compiler versions were found,
+ // otherwise we get makefile target collisions from sbsv2 toolchain.
+ if (rvctVersions.size()) {
+ debugClauses << configClause(item, debugBuild, defaultRvctCompilerVersion, genericArmClause);
+ releaseClauses << configClause(item, releaseBuild, defaultRvctCompilerVersion, genericArmClause);
+ } else {
+ debugClauses << configClause(item, debugBuild, defaultGcceCompilerVersion, armClause);
+ releaseClauses << configClause(item, releaseBuild, defaultGcceCompilerVersion, armClause);
+ }
+ }
+
+ allClauses << debugClauses << releaseClauses;
+
+ QTextStream t(&wrapperFile);
+
+ MakefileGenerator::writeHeader(t);
+
+ t << "MAKEFILE = " << fileInfo(wrapperFile.fileName()).fileName() << endl;
+ t << "QMAKE = " << var("QMAKE_QMAKE") << endl;
+ t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ t << "DEL_DIR = " << var("QMAKE_DEL_DIR") << endl;
+ t << "CHK_DIR_EXISTS = " << var("QMAKE_CHK_DIR_EXISTS") << endl;
+ t << "MKDIR = " << var("QMAKE_MKDIR") << endl;
+ t << "MOVE = " << var("QMAKE_MOVE") << endl;
+ t << "DEBUG_PLATFORMS = " << debugPlatforms.join(" ") << endl;
+ t << "RELEASE_PLATFORMS = " << releasePlatforms.join(" ") << endl;
+ t << "MAKE = make" << endl;
+ t << "SBS = sbs" << endl;
+ t << endl;
+ t << "DEFINES" << '\t' << " = "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << varGlue("QMAKE_COMPILER_DEFINES", "-D", "-D", " ")
+ << varGlue("DEFINES","-D"," -D","") << endl;
+
+ t << "INCPATH" << '\t' << " = ";
+
+ for (QMap<QString, QStringList>::iterator it = systeminclude.begin(); it != systeminclude.end(); ++it) {
+ QStringList values = it.value();
+ for (int i = 0; i < values.size(); ++i) {
+ t << " -I\"" << values.at(i) << "\" ";
+ }
+ }
+
+ t << endl;
+ t << "first: default" << endl << endl;
+ if (!isPrimaryMakefile) {
+ t << "all:" << endl << endl;
+ t << "default: all" << endl << endl;
+ } else {
+ t << "all: debug release" << endl << endl;
+ if (debugPlatforms.contains(winscwPlatform))
+ t << "default: debug-winscw";
+ else if (debugPlatforms.size())
+ t << "default: debug-" << debugPlatforms.first();
+ else
+ t << "default: all";
+ t << endl;
+
+ QString qmakeCmd = "\t$(QMAKE) \"" + project->projectFile() + "\" " + buildArgs();
+
+ t << "qmake:" << endl;
+ t << qmakeCmd << endl;
+ t << endl;
+
+ t << BLD_INF_FILENAME ": " << project->projectFile() << endl;
+ t << qmakeCmd << endl;
+ t << endl;
+
+ QString locFileDep = generateLocFileTarget(t, qmakeCmd);
+
+ t << "debug: " << locFileDep << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS)";
+ foreach(QString clause, debugClauses) {
+ t << clause;
+ }
+ t << endl;
+ t << "clean-debug: " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) reallyclean --toolcheck=off";
+ foreach(QString clause, debugClauses) {
+ t << clause;
+ }
+ t << endl;
+
+ t << "freeze-debug: " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) freeze";
+ foreach(QString clause, debugClauses) {
+ t << clause;
+ }
+ t << endl;
+
+ t << "release: " << locFileDep << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS)";
+ foreach(QString clause, releaseClauses) {
+ t << clause;
+ }
+ t << endl;
+ t << "clean-release: " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) reallyclean --toolcheck=off";
+ foreach(QString clause, releaseClauses) {
+ t << clause;
+ }
+ t << endl;
+
+ t << "freeze-release: " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) freeze";
+ foreach(QString clause, releaseClauses) {
+ t << clause;
+ }
+ t << endl << endl;
+
+ QString defaultGcceArmVersion;
+ if (armPlatforms.size()) {
+ defaultGcceArmVersion = armPlatforms.first();
+ } else {
+ defaultGcceArmVersion = QLatin1String("armv5");
+ }
+
+ // For more specific builds, targets are in this form:
+ // release-armv5 - generic target, compiler version determined by toolchain or autodetection
+ // release-armv5-rvct4.0 - compiler version specific target
+ foreach(QString item, debugPlatforms) {
+ QString clause;
+ if (item.compare(winscwPlatform) == 0)
+ clause = configClause(item, debugBuild, QString(), winscwClause);
+ else if (item.compare(gccePlatform) == 0 )
+ clause = configClause(defaultGcceArmVersion, debugBuild, defaultGcceCompilerVersion, armClause);
+ else // use generic arm clause
+ clause = configClause(item, debugBuild, defaultRvctCompilerVersion, genericArmClause);
+
+ t << "debug-" << item << ": " << locFileDep << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS)" << clause << endl;
+ t << "clean-debug-" << item << ": " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) reallyclean" << clause << endl;
+ t << "freeze-debug-" << item << ": " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) freeze" << clause << endl;
+ }
+
+ foreach(QString item, releasePlatforms) {
+ QString clause;
+ if (item.compare(gccePlatform) == 0 )
+ clause = configClause(defaultGcceArmVersion, releaseBuild, defaultGcceCompilerVersion, armClause);
+ else // use generic arm clause
+ clause = configClause(item, releaseBuild, defaultRvctCompilerVersion, genericArmClause);
+
+ t << "release-" << item << ": " << locFileDep << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS)" << clause << endl;
+ t << "clean-release-" << item << ": " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) reallyclean" << clause << endl;
+ t << "freeze-release-" << item << ": " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) freeze" << clause << endl;
+ }
+
+ foreach(QString item, armPlatforms) {
+ foreach(QString compilerVersion, allArmCompilerVersions) {
+ QString debugClause = configClause(item, debugBuild, compilerVersion, armClause);
+ QString releaseClause = configClause(item, releaseBuild, compilerVersion, armClause);
+ t << "debug-" << item << "-" << compilerVersion << ": " << locFileDep << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS)" << debugClause << endl;
+ t << "clean-debug-" << item << "-" << compilerVersion << ": " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) reallyclean" << debugClause << endl;
+ t << "freeze-debug-" << item << "-" << compilerVersion << ": " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) freeze" << debugClause << endl;
+ t << "release-" << item << "-" << compilerVersion << ": " << locFileDep << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS)" << releaseClause << endl;
+ t << "clean-release-" << item << "-" << compilerVersion << ": " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) reallyclean" << releaseClause << endl;
+ t << "freeze-release-" << item << "-" << compilerVersion << ": " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) freeze" << releaseClause << endl;
+ }
+ }
+
+ t << endl;
+ t << "export: " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) export";
+ foreach(QString clause, allClauses) {
+ t << clause;
+ }
+ t << endl << endl;
+
+ t << "cleanexport: " << BLD_INF_FILENAME << endl;
+ t << "\t$(SBS) cleanexport";
+ foreach(QString clause, allClauses) {
+ t << clause;
+ }
+ t << endl << endl;
+
+ // Typically one wants to freeze release binaries, so make plain freeze target equal to
+ // freeze-release. If freezing of debug binaries is needed for some reason, then
+ // freeze-debug target should be used. There is no point to try freezing both with one
+ // target as both produce the same def file.
+ t << "freeze: freeze-release" << endl << endl;
+ }
+
+ // Add all extra targets including extra compiler targets also to wrapper makefile,
+ // even though many of them may have already been added to bld.inf as FLMs.
+ // This is to enable use of targets like 'mocables', which call targets generated by extra compilers.
+ if (targetType != TypeSubdirs) {
+ t << extraTargetsCache;
+ t << extraCompilersCache;
+ } else {
+ QList<MakefileGenerator::SubTarget*> subtargets = findSubDirsSubTargets();
+ writeSubTargets(t, subtargets, SubTargetSkipDefaultVariables|SubTargetSkipDefaultTargets);
+ qDeleteAll(subtargets);
+ }
+
+ generateDistcleanTargets(t);
+
+ // Do not check for tools when doing generic clean, as most tools are not actually needed for
+ // cleaning. Mainly this is relevant for environments that do not have winscw compiler.
+ t << "clean: " << BLD_INF_FILENAME << endl;
+ t << "\t-$(SBS) reallyclean --toolcheck=off";
+ foreach(QString clause, allClauses) {
+ t << clause;
+ }
+ t << endl << endl;
+
+ t << endl;
+}
+
+void SymbianSbsv2MakefileGenerator::writeBldInfExtensionRulesPart(QTextStream& t, const QString &iconTargetFile)
+{
+ // Makes sure we have needed FLMs in place.
+ exportFlm();
+
+ // Parse extra compilers data
+ QStringList defines;
+ QStringList incPath;
+
+ defines << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << varGlue("QMAKE_COMPILER_DEFINES", "-D", "-D", " ")
+ << varGlue("DEFINES","-D"," -D","");
+ for (QMap<QString, QStringList>::iterator it = systeminclude.begin(); it != systeminclude.end(); ++it) {
+ QStringList values = it.value();
+ for (int i = 0; i < values.size(); ++i) {
+ incPath << QLatin1String(" -I\"") + values.at(i) + "\"";
+ }
+ }
+
+ QMap<QString, QString> commandsToReplace;
+ commandsToReplace.insert(project->values("QMAKE_COPY").join(" "),
+ project->values("QMAKE_SBSV2_COPY").join(" "));
+ commandsToReplace.insert(project->values("QMAKE_COPY_DIR").join(" "),
+ project->values("QMAKE_SBSV2_COPY_DIR").join(" "));
+ commandsToReplace.insert(project->values("QMAKE_MOVE").join(" "),
+ project->values("QMAKE_SBSV2_MOVE").join(" "));
+ commandsToReplace.insert(project->values("QMAKE_DEL_FILE").join(" "),
+ project->values("QMAKE_SBSV2_DEL_FILE").join(" "));
+ commandsToReplace.insert(project->values("QMAKE_MKDIR").join(" "),
+ project->values("QMAKE_SBSV2_MKDIR").join(" "));
+ commandsToReplace.insert(project->values("QMAKE_DEL_DIR").join(" "),
+ project->values("QMAKE_SBSV2_DEL_DIR").join(" "));
+ commandsToReplace.insert(project->values("QMAKE_DEL_TREE").join(" "),
+ project->values("QMAKE_SBSV2_DEL_TREE").join(" "));
+
+ // Write extra compilers and targets to initialize QMAKE_ET_* variables
+ // Cache results to avoid duplicate calls when creating wrapper makefile
+ QTextStream extraCompilerStream(&extraCompilersCache);
+ QTextStream extraTargetStream(&extraTargetsCache);
+ writeExtraCompilerTargets(extraCompilerStream);
+ writeExtraTargets(extraTargetStream);
+
+ // Figure out everything the target depends on as we don't want to run extra targets that
+ // are not necessary.
+ QStringList allPreDeps;
+ foreach(QString item, project->values("PRE_TARGETDEPS")) {
+ allPreDeps.append(fileInfo(item).absoluteFilePath());
+ }
+
+ foreach (QString item, project->values("GENERATED_SOURCES")) {
+ allPreDeps.append(fileInfo(item).absoluteFilePath());
+ }
+
+ for (QMap<QString, QStringList>::iterator it = sources.begin(); it != sources.end(); ++it) {
+ QString currentSourcePath = it.key();
+ QStringList values = it.value();
+ for (int i = 0; i < values.size(); ++i) {
+ QString sourceFile = currentSourcePath + "/" + values.at(i);
+ QStringList deps = findDependencies(QDir::toNativeSeparators(sourceFile));
+ foreach(QString depItem, deps) {
+ appendIfnotExist(allPreDeps, fileInfo(depItem).absoluteFilePath());
+ }
+ }
+ }
+
+ // Write FLM rules for all extra targets and compilers that we depend on to build the target.
+ QStringList extraTargets;
+ extraTargets << project->values("QMAKE_EXTRA_TARGETS") << project->values("QMAKE_EXTRA_COMPILERS");
+ foreach(QString item, extraTargets) {
+ foreach(QString targetItem, project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + item)) {
+ // Make sure targetpath is absolute
+ QString absoluteTarget = fileInfo(targetItem).absoluteFilePath();
+ if (allPreDeps.contains(absoluteTarget)) {
+ QStringList deps = project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + item + targetItem);
+ QString commandItem = project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + item + targetItem).join(" ");
+
+ // Make sure all deps paths are absolute
+ QString absoluteDeps;
+ foreach (QString depItem, deps) {
+ if (!depItem.isEmpty()) {
+ absoluteDeps.append(fileInfo(depItem).absoluteFilePath());
+ absoluteDeps.append(" ");
+ }
+ }
+
+ t << "START EXTENSION qt/qmake_extra_pre_targetdep.export" << endl;
+ t << "OPTION PREDEP_TARGET " << absoluteTarget << endl;
+ t << "OPTION DEPS " << absoluteDeps << endl;
+
+ if (commandItem.indexOf("$(INCPATH)") != -1)
+ commandItem.replace("$(INCPATH)", incPath.join(" "));
+ if (commandItem.indexOf("$(DEFINES)") != -1)
+ commandItem.replace("$(DEFINES)", defines.join(" "));
+
+ fixFlmCmd(&commandItem, commandsToReplace);
+
+ t << "OPTION COMMAND " << commandItem << endl;
+ t << "END" << endl;
+ }
+ }
+ }
+
+ t << endl;
+
+ // Write deployment rules
+ QString remoteTestPath = qt_epocRoot() + QLatin1String("epoc32/winscw/c/private/") + privateDirUid;
+ DeploymentList depList;
+
+ //write emulator deployment
+ t << "#if defined(WINSCW)" << endl;
+ initProjectDeploySymbian(project, depList, remoteTestPath, false, true,
+ QLatin1String(EMULATOR_DEPLOYMENT_PLATFORM), QString(), generatedDirs, generatedFiles);
+ writeSbsDeploymentList(depList, t);
+ t << "#endif" << endl;
+
+ //write ROM deployment
+ remoteTestPath = qt_epocRoot() + QLatin1String("epoc32/data/z/private/") + privateDirUid;
+ depList.clear();
+ initProjectDeploySymbian(project, depList, remoteTestPath, false, true,
+ QLatin1String(ROM_DEPLOYMENT_PLATFORM), QString(), generatedDirs, generatedFiles);
+ writeSbsDeploymentList(depList, t);
+ t << endl;
+
+ // Write post link rules
+ if (!project->isEmpty("QMAKE_POST_LINK")) {
+ QString postLinkCmd = var("QMAKE_POST_LINK");
+ fixFlmCmd(&postLinkCmd, commandsToReplace);
+ t << "START EXTENSION qt/qmake_post_link" << endl;
+ t << "OPTION POST_LINK_CMD " << postLinkCmd << endl;
+ t << "OPTION LINK_TARGET " << fixedTarget << QLatin1String(".") << getTargetExtension() << endl;
+ t << "END" << endl;
+ t << endl;
+ }
+
+ // Application icon generation
+ QStringList icons = project->values("ICON");
+ if (icons.size()) {
+ QString icon = icons.first();
+ if (icons.size() > 1)
+ fprintf(stderr, "Warning: Only first icon specified in ICON variable is used: '%s'.", qPrintable(icon));
+
+ t << "START EXTENSION s60/mifconv" << endl;
+
+ QFileInfo iconInfo = fileInfo(icon);
+
+ QFileInfo bldinf(project->values("MAKEFILE").first());
+ QString iconPath = bldinf.dir().relativeFilePath(iconInfo.path());
+
+ QString iconFile = iconInfo.baseName();
+
+ QFileInfo iconTargetInfo = fileInfo(iconTargetFile);
+ QString iconTarget = iconTargetInfo.fileName();
+
+ t << "OPTION SOURCES -c32 " << iconFile << endl;
+ t << "OPTION SOURCEDIR " << iconPath << endl;
+ t << "OPTION TARGETFILE " << iconTarget << endl;
+ t << "OPTION SVGENCODINGVERSION 3" << endl; // Compatibility with S60 3.1 devices and up
+ t << "END" << endl;
+ }
+
+ t << "START EXTENSION qt/qmake_store_build" << endl;
+ t << "END" << endl;
+ t << endl;
+
+ // Handle QMAKE_CLEAN
+ QStringList cleanFiles = project->values("QMAKE_CLEAN");
+ if (!cleanFiles.isEmpty()) {
+ QStringList absoluteCleanFiles;
+ foreach (QString cleanFile, cleanFiles) {
+ QFileInfo fi(cleanFile);
+ QString fileName = QLatin1String("\"");
+ fileName.append(fi.absoluteFilePath());
+ fileName.append(QLatin1String("\""));
+ absoluteCleanFiles << fileName;
+ }
+ t << "START EXTENSION qt/qmake_clean" << endl;
+ t << "OPTION CLEAN_FILES " << absoluteCleanFiles.join(" ") << endl;
+ t << "END" << endl;
+ }
+ t << endl;
+}
+
+void SymbianSbsv2MakefileGenerator::writeBldInfMkFilePart(QTextStream& t, bool addDeploymentExtension)
+{
+ // We don't generate extension makefile in sbsb2
+ Q_UNUSED(t);
+ Q_UNUSED(addDeploymentExtension);
+}
+
+void SymbianSbsv2MakefileGenerator::appendAbldTempDirs(QStringList& sysincspaths, QString includepath)
+{
+ //Do nothing
+ Q_UNUSED(sysincspaths);
+ Q_UNUSED(includepath);
+}
diff --git a/qmake/generators/symbian/symmake_sbsv2.h b/qmake/generators/symbian/symmake_sbsv2.h
new file mode 100644
index 0000000000..bec1034fbe
--- /dev/null
+++ b/qmake/generators/symbian/symmake_sbsv2.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SYMMAKE_SBSV2_H
+#define SYMMAKE_SBSV2_H
+
+#include <symmake.h>
+
+QT_BEGIN_NAMESPACE
+
+class SymbianSbsv2MakefileGenerator : public SymbianMakefileGenerator
+{
+protected:
+
+ // Inherited from parent
+ virtual void writeBldInfExtensionRulesPart(QTextStream& t, const QString &iconTargetFile);
+ virtual void writeBldInfMkFilePart(QTextStream& t, bool addDeploymentExtension);
+ virtual void writeMkFile(const QString& wrapperFileName, bool deploymentOnly);
+ virtual void writeWrapperMakefile(QFile& wrapperFile, bool isPrimaryMakefile);
+ virtual void appendAbldTempDirs(QStringList& sysincspaths, QString includepath);
+ virtual bool isForSymbianSbsv2() const { return true; } // FIXME: killme - i'm ugly!
+
+public:
+
+ SymbianSbsv2MakefileGenerator();
+ ~SymbianSbsv2MakefileGenerator();
+
+private:
+ void exportFlm();
+ void findGcceVersions(QStringList *gcceVersionList, QString *defaultVersion);
+ void findRvctVersions(QStringList *rvctVersionList, QString *defaultVersion);
+ void findInstalledCompilerVersions(const QString &matchExpression,
+ const QString &versionPrefix,
+ QStringList *versionList);
+ QString configClause(const QString &platform,
+ const QString &build,
+ const QString &compilerVersion,
+ const QString &clauseTemplate);
+
+ void writeSbsDeploymentList(const DeploymentList& depList, QTextStream& t);
+
+ QString extraTargetsCache;
+ QString extraCompilersCache;
+};
+
+#endif // SYMMAKE_SBSV2_H
diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp
new file mode 100644
index 0000000000..e659e62288
--- /dev/null
+++ b/qmake/generators/unix/unixmake.cpp
@@ -0,0 +1,925 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "unixmake.h"
+#include "option.h"
+#include <qregexp.h>
+#include <qfile.h>
+#include <qhash.h>
+#include <qdir.h>
+#include <time.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+void
+UnixMakefileGenerator::init()
+{
+ if(init_flag)
+ return;
+ init_flag = true;
+
+ if(project->isEmpty("QMAKE_EXTENSION_SHLIB")) {
+ if(project->isEmpty("QMAKE_CYGWIN_SHLIB")) {
+ project->values("QMAKE_EXTENSION_SHLIB").append("so");
+ } else {
+ project->values("QMAKE_EXTENSION_SHLIB").append("dll");
+ }
+ }
+
+ if (project->isEmpty("QMAKE_PREFIX_SHLIB"))
+ // Prevent crash when using the empty variable.
+ project->values("QMAKE_PREFIX_SHLIB").append("");
+
+ if(!project->isEmpty("QMAKE_FAILED_REQUIREMENTS")) /* no point */
+ return;
+
+ QStringList &configs = project->values("CONFIG");
+ if(project->isEmpty("ICON") && !project->isEmpty("RC_FILE"))
+ project->values("ICON") = project->values("RC_FILE");
+ if(project->isEmpty("QMAKE_EXTENSION_PLUGIN"))
+ project->values("QMAKE_EXTENSION_PLUGIN").append(project->first("QMAKE_EXTENSION_SHLIB"));
+ if(project->isEmpty("QMAKE_COPY_FILE"))
+ project->values("QMAKE_COPY_FILE").append("$(COPY)");
+ if(project->isEmpty("QMAKE_STREAM_EDITOR"))
+ project->values("QMAKE_STREAM_EDITOR").append("sed");
+ if(project->isEmpty("QMAKE_COPY_DIR"))
+ project->values("QMAKE_COPY_DIR").append("$(COPY) -R");
+ if(project->isEmpty("QMAKE_INSTALL_FILE"))
+ project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_DIR"))
+ project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
+ if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
+ project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_LIBTOOL"))
+ project->values("QMAKE_LIBTOOL").append("libtool --silent");
+ if(project->isEmpty("QMAKE_SYMBOLIC_LINK"))
+ project->values("QMAKE_SYMBOLIC_LINK").append("ln -f -s");
+
+ /* this should probably not be here, but I'm using it to wrap the .t files */
+ if(project->first("TEMPLATE") == "app")
+ project->values("QMAKE_APP_FLAG").append("1");
+ else if(project->first("TEMPLATE") == "lib")
+ project->values("QMAKE_LIB_FLAG").append("1");
+ else if(project->first("TEMPLATE") == "subdirs") {
+ MakefileGenerator::init();
+ if(project->isEmpty("MAKEFILE"))
+ project->values("MAKEFILE").append("Makefile");
+ if(project->values("QMAKE_INTERNAL_QMAKE_DEPS").indexOf("qmake_all") == -1)
+ project->values("QMAKE_INTERNAL_QMAKE_DEPS").append("qmake_all");
+ return; /* subdirs is done */
+ }
+
+ //If the TARGET looks like a path split it into DESTDIR and the resulting TARGET
+ if(!project->isEmpty("TARGET")) {
+ project->values("TARGET") = escapeFilePaths(project->values("TARGET"));
+ QString targ = unescapeFilePath(project->first("TARGET"));
+ int slsh = qMax(targ.lastIndexOf('/'), targ.lastIndexOf(Option::dir_sep));
+ if(slsh != -1) {
+ if(project->isEmpty("DESTDIR"))
+ project->values("DESTDIR").append("");
+ else if(project->first("DESTDIR").right(1) != Option::dir_sep)
+ project->values("DESTDIR") = QStringList(project->first("DESTDIR") + Option::dir_sep);
+ project->values("DESTDIR") = QStringList(project->first("DESTDIR") + targ.left(slsh+1));
+ project->values("TARGET") = QStringList(targ.mid(slsh+1));
+ }
+ }
+
+ project->values("QMAKE_ORIG_TARGET") = project->values("TARGET");
+ project->values("QMAKE_ORIG_DESTDIR") = project->values("DESTDIR");
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
+ project->values("QMAKE_LIBS_PRIVATE") += escapeFilePaths(project->values("LIBS_PRIVATE"));
+ if((!project->isEmpty("QMAKE_LIB_FLAG") && !project->isActiveConfig("staticlib")) ||
+ (project->isActiveConfig("qt") && project->isActiveConfig("plugin"))) {
+ if(configs.indexOf("dll") == -1) configs.append("dll");
+ } else if(!project->isEmpty("QMAKE_APP_FLAG") || project->isActiveConfig("dll")) {
+ configs.removeAll("staticlib");
+ }
+ if(!project->isEmpty("QMAKE_INCREMENTAL"))
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_INCREMENTAL");
+ else if(!project->isEmpty("QMAKE_LFLAGS_PREBIND") &&
+ !project->values("QMAKE_LIB_FLAG").isEmpty() &&
+ project->isActiveConfig("dll"))
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PREBIND");
+ if(!project->isEmpty("QMAKE_INCDIR"))
+ project->values("INCLUDEPATH") += project->values("QMAKE_INCDIR");
+ if(!project->isEmpty("QMAKE_LIBDIR")) {
+ const QStringList &libdirs = project->values("QMAKE_LIBDIR");
+ for(int i = 0; i < libdirs.size(); ++i) {
+ if(!project->isEmpty("QMAKE_LFLAGS_RPATH") && project->isActiveConfig("rpath_libdirs"))
+ project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + libdirs[i];
+ if (project->isActiveConfig("rvct_linker")) {
+ project->values("QMAKE_LIBDIR_FLAGS") += "--userlibpath " + escapeFilePath(libdirs[i]);
+ } else if (project->isActiveConfig("armcc_linker")) {
+ project->values("QMAKE_LIBDIR_FLAGS") += "-L--userlibpath=" + escapeFilePath(libdirs[i]);
+ } else {
+ project->values("QMAKE_LIBDIR_FLAGS") += "-L" + escapeFilePath(libdirs[i]);
+ }
+ }
+ }
+ if(project->isActiveConfig("macx") && !project->isEmpty("QMAKE_FRAMEWORKPATH")) {
+ const QStringList &fwdirs = project->values("QMAKE_FRAMEWORKPATH");
+ for(int i = 0; i < fwdirs.size(); ++i) {
+ project->values("QMAKE_FRAMEWORKPATH_FLAGS") += "-F" + escapeFilePath(fwdirs[i]);
+ }
+ }
+ if(!project->isEmpty("QMAKE_RPATHDIR")) {
+ const QStringList &rpathdirs = project->values("QMAKE_RPATHDIR");
+ for(int i = 0; i < rpathdirs.size(); ++i) {
+ if(!project->isEmpty("QMAKE_LFLAGS_RPATH"))
+ project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + escapeFilePath(QFileInfo(rpathdirs[i]).absoluteFilePath());
+ }
+ }
+
+ project->values("QMAKE_FILETAGS") << "SOURCES" << "GENERATED_SOURCES" << "TARGET" << "DESTDIR";
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(int i = 0; i < quc.size(); ++i)
+ project->values("QMAKE_FILETAGS") += project->values(quc[i]+".input");
+ }
+
+ if(project->isActiveConfig("GNUmake") && !project->isEmpty("QMAKE_CFLAGS_DEPS"))
+ include_deps = true; //do not generate deps
+ if(project->isActiveConfig("compile_libtool"))
+ Option::obj_ext = ".lo"; //override the .o
+
+ MakefileGenerator::init();
+
+ QString comps[] = { "C", "CXX", "OBJC", "OBJCXX", QString() };
+ for(int i = 0; !comps[i].isNull(); i++) {
+ QString compile_flag = var("QMAKE_COMPILE_FLAG");
+ if(compile_flag.isEmpty())
+ compile_flag = "-c";
+
+ if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")) {
+ QString pchFlags = var("QMAKE_" + comps[i] + "FLAGS_USE_PRECOMPILE");
+
+ QString pchBaseName;
+ if(!project->isEmpty("PRECOMPILED_DIR")) {
+ pchBaseName = Option::fixPathToTargetOS(project->first("PRECOMPILED_DIR"));
+ if(!pchBaseName.endsWith(Option::dir_sep))
+ pchBaseName += Option::dir_sep;
+ }
+ pchBaseName += project->first("QMAKE_ORIG_TARGET");
+
+ // replace place holders
+ pchFlags = pchFlags.replace("${QMAKE_PCH_INPUT}",
+ fileFixify(project->first("PRECOMPILED_HEADER")));
+ pchFlags = pchFlags.replace("${QMAKE_PCH_OUTPUT_BASE}", pchBaseName);
+ if (project->isActiveConfig("icc_pch_style")) {
+ // icc style
+ pchFlags = pchFlags.replace("${QMAKE_PCH_OUTPUT}",
+ pchBaseName + project->first("QMAKE_PCH_OUTPUT_EXT"));
+ } else {
+ // gcc style (including clang_pch_style)
+ QString headerPrefix = project->first("QMAKE_PRECOMP_PREFIX");
+ QString headerSuffix;
+ if (project->isActiveConfig("clang_pch_style"))
+ headerSuffix = project->first("QMAKE_PCH_OUTPUT_EXT");
+ else
+ pchBaseName += project->first("QMAKE_PCH_OUTPUT_EXT");
+
+ pchBaseName += Option::dir_sep;
+ QString pchOutputFile;
+
+ if(comps[i] == "C") {
+ pchOutputFile = "c";
+ } else if(comps[i] == "CXX") {
+ pchOutputFile = "c++";
+ } else if(project->isActiveConfig("objective_c")) {
+ if(comps[i] == "OBJC")
+ pchOutputFile = "objective-c";
+ else if(comps[i] == "OBJCXX")
+ pchOutputFile = "objective-c++";
+ }
+
+ if(!pchOutputFile.isEmpty()) {
+ pchFlags = pchFlags.replace("${QMAKE_PCH_OUTPUT}",
+ pchBaseName + pchOutputFile + headerSuffix);
+ }
+ }
+
+ if (!pchFlags.isEmpty())
+ compile_flag += " " + pchFlags;
+ }
+
+ QString cflags;
+ if(comps[i] == "OBJC" || comps[i] == "OBJCXX")
+ cflags += " $(CFLAGS)";
+ else
+ cflags += " $(" + comps[i] + "FLAGS)";
+ compile_flag += cflags + " $(INCPATH)";
+
+ QString compiler = comps[i];
+ if (compiler == "C")
+ compiler = "CC";
+
+ QString runComp = "QMAKE_RUN_" + compiler;
+ if(project->isEmpty(runComp))
+ project->values(runComp).append("$(" + compiler + ") " + compile_flag + " -o $obj $src");
+ QString runCompImp = "QMAKE_RUN_" + compiler + "_IMP";
+ if(project->isEmpty(runCompImp))
+ project->values(runCompImp).append("$(" + compiler + ") " + compile_flag + " -o \"$@\" \"$<\"");
+ }
+
+ if(project->isActiveConfig("macx") && !project->isEmpty("TARGET") && !project->isActiveConfig("compile_libtool") &&
+ ((project->isActiveConfig("build_pass") || project->isEmpty("BUILDS")))) {
+ QString bundle;
+ if(project->isActiveConfig("bundle") && !project->isEmpty("QMAKE_BUNDLE_EXTENSION")) {
+ bundle = unescapeFilePath(project->first("TARGET"));
+ if(!project->isEmpty("QMAKE_BUNDLE_NAME"))
+ bundle = unescapeFilePath(project->first("QMAKE_BUNDLE_NAME"));
+ if(!bundle.endsWith(project->first("QMAKE_BUNDLE_EXTENSION")))
+ bundle += project->first("QMAKE_BUNDLE_EXTENSION");
+ } else if(project->first("TEMPLATE") == "app" && project->isActiveConfig("app_bundle")) {
+ bundle = unescapeFilePath(project->first("TARGET"));
+ if(!project->isEmpty("QMAKE_APPLICATION_BUNDLE_NAME"))
+ bundle = unescapeFilePath(project->first("QMAKE_APPLICATION_BUNDLE_NAME"));
+ if(!bundle.endsWith(".app"))
+ bundle += ".app";
+ if(project->isEmpty("QMAKE_BUNDLE_LOCATION"))
+ project->values("QMAKE_BUNDLE_LOCATION").append("Contents/MacOS");
+ project->values("QMAKE_PKGINFO").append(project->first("DESTDIR") + bundle + "/Contents/PkgInfo");
+ project->values("QMAKE_BUNDLE_RESOURCE_FILE").append(project->first("DESTDIR") + bundle + "/Contents/Resources/empty.lproj");
+ } else if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") &&
+ ((!project->isActiveConfig("plugin") && project->isActiveConfig("lib_bundle")) ||
+ (project->isActiveConfig("plugin") && project->isActiveConfig("plugin_bundle")))) {
+ bundle = unescapeFilePath(project->first("TARGET"));
+ if(project->isActiveConfig("plugin")) {
+ if(!project->isEmpty("QMAKE_PLUGIN_BUNDLE_NAME"))
+ bundle = unescapeFilePath(project->first("QMAKE_PLUGIN_BUNDLE_NAME"));
+ if(!project->isEmpty("QMAKE_BUNDLE_EXTENSION") && !bundle.endsWith(project->first("QMAKE_BUNDLE_EXTENSION")))
+ bundle += project->first("QMAKE_BUNDLE_EXTENSION");
+ else if(!bundle.endsWith(".plugin"))
+ bundle += ".plugin";
+ if(project->isEmpty("QMAKE_BUNDLE_LOCATION"))
+ project->values("QMAKE_BUNDLE_LOCATION").append("Contents/MacOS");
+ } else {
+ if(!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME"))
+ bundle = unescapeFilePath(project->first("QMAKE_FRAMEWORK_BUNDLE_NAME"));
+ if(!project->isEmpty("QMAKE_BUNDLE_EXTENSION") && !bundle.endsWith(project->first("QMAKE_BUNDLE_EXTENSION")))
+ bundle += project->first("QMAKE_BUNDLE_EXTENSION");
+ else if(!bundle.endsWith(".framework"))
+ bundle += ".framework";
+ }
+ }
+ if(!bundle.isEmpty()) {
+ project->values("QMAKE_BUNDLE") = QStringList(bundle);
+ project->values("ALL_DEPS") += project->first("QMAKE_PKGINFO");
+ project->values("ALL_DEPS") += project->first("QMAKE_BUNDLE_RESOURCE_FILE");
+ } else {
+ project->values("QMAKE_BUNDLE").clear();
+ project->values("QMAKE_BUNDLE_LOCATION").clear();
+ }
+ } else { //no bundling here
+ project->values("QMAKE_BUNDLE").clear();
+ project->values("QMAKE_BUNDLE_LOCATION").clear();
+ }
+
+ if(!project->isEmpty("QMAKE_INTERNAL_INCLUDED_FILES"))
+ project->values("DISTFILES") += project->values("QMAKE_INTERNAL_INCLUDED_FILES");
+ project->values("DISTFILES") += project->projectFile();
+
+ init2();
+ project->values("QMAKE_INTERNAL_PRL_LIBS") << "QMAKE_LIBDIR_FLAGS" << "QMAKE_FRAMEWORKPATH_FLAGS" << "QMAKE_LIBS";
+ if(!project->isEmpty("QMAKE_MAX_FILES_PER_AR")) {
+ bool ok;
+ int max_files = project->first("QMAKE_MAX_FILES_PER_AR").toInt(&ok);
+ QStringList ar_sublibs, objs = project->values("OBJECTS");
+ if(ok && max_files > 5 && max_files < (int)objs.count()) {
+ QString lib;
+ for(int i = 0, obj_cnt = 0, lib_cnt = 0; i != objs.size(); ++i) {
+ if((++obj_cnt) >= max_files) {
+ if(lib_cnt) {
+ lib.sprintf("lib%s-tmp%d.a",
+ project->first("QMAKE_ORIG_TARGET").toLatin1().constData(), lib_cnt);
+ ar_sublibs << lib;
+ obj_cnt = 0;
+ }
+ lib_cnt++;
+ }
+ }
+ }
+ if(!ar_sublibs.isEmpty()) {
+ project->values("QMAKE_AR_SUBLIBS") = ar_sublibs;
+ project->values("QMAKE_INTERNAL_PRL_LIBS") << "QMAKE_AR_SUBLIBS";
+ }
+ }
+
+ if(project->isActiveConfig("compile_libtool")) {
+ const QString libtoolify[] = { "QMAKE_RUN_CC", "QMAKE_RUN_CC_IMP",
+ "QMAKE_RUN_CXX", "QMAKE_RUN_CXX_IMP",
+ "QMAKE_LINK_THREAD", "QMAKE_LINK", "QMAKE_AR_CMD", "QMAKE_LINK_SHLIB_CMD",
+ QString() };
+ for(int i = 0; !libtoolify[i].isNull(); i++) {
+ QStringList &l = project->values(libtoolify[i]);
+ if(!l.isEmpty()) {
+ QString libtool_flags, comp_flags;
+ if(libtoolify[i].startsWith("QMAKE_LINK") || libtoolify[i] == "QMAKE_AR_CMD") {
+ libtool_flags += " --mode=link";
+ if(project->isActiveConfig("staticlib")) {
+ libtool_flags += " -static";
+ } else {
+ if(!project->isEmpty("QMAKE_LIB_FLAG")) {
+ int maj = project->first("VER_MAJ").toInt();
+ int min = project->first("VER_MIN").toInt();
+ int pat = project->first("VER_PAT").toInt();
+ comp_flags += " -version-info " + QString::number(10*maj + min) +
+ ":" + QString::number(pat) + ":0";
+ if(libtoolify[i] != "QMAKE_AR_CMD") {
+ QString rpath = Option::output_dir;
+ if(!project->isEmpty("DESTDIR")) {
+ rpath = project->first("DESTDIR");
+ if(QDir::isRelativePath(rpath))
+ rpath.prepend(Option::output_dir + Option::dir_sep);
+ }
+ comp_flags += " -rpath " + Option::fixPathToTargetOS(rpath, false);
+ }
+ }
+ }
+ if(project->isActiveConfig("plugin"))
+ libtool_flags += " -module";
+ } else {
+ libtool_flags += " --mode=compile";
+ }
+ l.first().prepend("$(LIBTOOL)" + libtool_flags + " ");
+ if(!comp_flags.isEmpty())
+ l.first() += comp_flags;
+ }
+ }
+ }
+}
+
+void
+UnixMakefileGenerator::processPrlVariable(const QString &var, const QStringList &l)
+{
+ if(var == "QMAKE_PRL_LIBS") {
+ project->values("QMAKE_CURRENT_PRL_LIBS") += l;
+ } else
+ MakefileGenerator::processPrlVariable(var, l);
+}
+
+QStringList
+&UnixMakefileGenerator::findDependencies(const QString &file)
+{
+ QStringList &ret = MakefileGenerator::findDependencies(file);
+ // Note: The QMAKE_IMAGE_COLLECTION file have all images
+ // as dependency, so don't add precompiled header then
+ if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")
+ && file != project->first("QMAKE_IMAGE_COLLECTION")) {
+ QString header_prefix;
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ header_prefix = project->first("PRECOMPILED_DIR");
+ header_prefix += project->first("QMAKE_ORIG_TARGET");
+ if (!project->isActiveConfig("clang_pch_style"))
+ header_prefix += project->first("QMAKE_PCH_OUTPUT_EXT");
+ if (project->isActiveConfig("icc_pch_style")) {
+ // icc style
+ for(QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
+ if(file.endsWith(*it)) {
+ ret += header_prefix;
+ break;
+ }
+ }
+ } else {
+ // gcc style (including clang_pch_style)
+ QString header_suffix = project->isActiveConfig("clang_pch_style")
+ ? project->first("QMAKE_PCH_OUTPUT_EXT") : "";
+ header_prefix += Option::dir_sep + project->first("QMAKE_PRECOMP_PREFIX");
+ for(QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
+ if(file.endsWith(*it)) {
+ if(!project->isEmpty("QMAKE_CFLAGS_PRECOMPILE")) {
+ QString precomp_c_h = header_prefix + "c" + header_suffix;
+ if(!ret.contains(precomp_c_h))
+ ret += precomp_c_h;
+ }
+ if(project->isActiveConfig("objective_c")) {
+ if(!project->isEmpty("QMAKE_OBJCFLAGS_PRECOMPILE")) {
+ QString precomp_objc_h = header_prefix + "objective-c" + header_suffix;
+ if(!ret.contains(precomp_objc_h))
+ ret += precomp_objc_h;
+ }
+ if(!project->isEmpty("QMAKE_OBJCXXFLAGS_PRECOMPILE")) {
+ QString precomp_objcpp_h = header_prefix + "objective-c++" + header_suffix;
+ if(!ret.contains(precomp_objcpp_h))
+ ret += precomp_objcpp_h;
+ }
+ }
+ break;
+ }
+ }
+ for(QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
+ if(file.endsWith(*it)) {
+ if(!project->isEmpty("QMAKE_CXXFLAGS_PRECOMPILE")) {
+ QString precomp_cpp_h = header_prefix + "c++" + header_suffix;
+ if(!ret.contains(precomp_cpp_h))
+ ret += precomp_cpp_h;
+ }
+ if(project->isActiveConfig("objective_c")) {
+ if(!project->isEmpty("QMAKE_OBJCXXFLAGS_PRECOMPILE")) {
+ QString precomp_objcpp_h = header_prefix + "objective-c++" + header_suffix;
+ if(!ret.contains(precomp_objcpp_h))
+ ret += precomp_objcpp_h;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+bool
+UnixMakefileGenerator::findLibraries()
+{
+ QList<QMakeLocalFileName> libdirs, frameworkdirs;
+ frameworkdirs.append(QMakeLocalFileName("/System/Library/Frameworks"));
+ frameworkdirs.append(QMakeLocalFileName("/Library/Frameworks"));
+ const QString lflags[] = { "QMAKE_LIBDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS", "QMAKE_LFLAGS", "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", QString() };
+ for(int i = 0; !lflags[i].isNull(); i++) {
+ QStringList &l = project->values(lflags[i]);
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ bool do_suffix = true;
+ QString stub, dir, extn, opt = (*it).trimmed();
+ if(opt.startsWith("-")) {
+ if(opt.startsWith("-L")) {
+ QMakeLocalFileName f(opt.right(opt.length()-2));
+ if(!libdirs.contains(f))
+ libdirs.append(f);
+ } else if(opt.startsWith("-l")) {
+ if (!project->isEmpty("QMAKE_RVCT_LINKSTYLE")) {
+ (*it) = opt.mid(2);
+ } else if (project->isActiveConfig("rvct_linker") || project->isActiveConfig("armcc_linker")) {
+ (*it) = "lib" + opt.mid(2) + ".so";
+ } else {
+ stub = opt.mid(2);
+ }
+ } else if(Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-F")) {
+ frameworkdirs.append(QMakeLocalFileName(opt.right(opt.length()-2)));
+ } else if(Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-framework")) {
+ if(opt.length() > 11) {
+ opt = opt.mid(11);
+ } else {
+ ++it;
+ opt = (*it);
+ }
+ do_suffix = false;
+ extn = "";
+ dir = "/System/Library/Frameworks/" + opt + ".framework/";
+ stub = opt;
+ }
+ } else {
+ extn = dir = "";
+ stub = opt;
+ int slsh = opt.lastIndexOf(Option::dir_sep);
+ if(slsh != -1) {
+ dir = opt.left(slsh);
+ stub = opt.mid(slsh+1);
+ }
+ QRegExp stub_reg("^.*lib(" + stub + "[^./=]*)\\.(.*)$");
+ if(stub_reg.exactMatch(stub)) {
+ stub = stub_reg.cap(1);
+ extn = stub_reg.cap(2);
+ }
+ }
+ if(!stub.isEmpty()) {
+ if(do_suffix && !project->isEmpty("QMAKE_" + stub.toUpper() + "_SUFFIX"))
+ stub += project->first("QMAKE_" + stub.toUpper() + "_SUFFIX");
+ bool found = false;
+ QStringList extens;
+ if(!extn.isNull())
+ extens << extn;
+ else if (!project->isEmpty("QMAKE_SYMBIAN_SHLIB"))
+ // In Symbian you link to the stub .lib file, but run with the .dll file.
+ extens << "lib";
+ else
+ extens << project->values("QMAKE_EXTENSION_SHLIB").first() << "a";
+ for(QStringList::Iterator extit = extens.begin(); extit != extens.end(); ++extit) {
+ if(dir.isNull()) {
+ for(QList<QMakeLocalFileName>::Iterator dep_it = libdirs.begin(); dep_it != libdirs.end(); ++dep_it) {
+ QString pathToLib = ((*dep_it).local() + Option::dir_sep
+ + project->values("QMAKE_PREFIX_SHLIB").first()
+ + stub + "." + (*extit));
+ if(exists(pathToLib)) {
+ if (!project->isEmpty("QMAKE_RVCT_LINKSTYLE"))
+ (*it) = pathToLib;
+ else
+ (*it) = "-l" + stub;
+ found = true;
+ break;
+ }
+ }
+ } else {
+ if(exists(project->values("QMAKE_PREFIX_SHLIB").first() + stub + "." + (*extit))) {
+ (*it) = project->values("QMAKE_PREFIX_SHLIB").first() + stub + "." + (*extit);
+ found = true;
+ break;
+ }
+ }
+ }
+ if(!found && project->isActiveConfig("compile_libtool")) {
+ for(int dep_i = 0; dep_i < libdirs.size(); ++dep_i) {
+