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) {
+ if(exists(libdirs[dep_i].local() + Option::dir_sep + project->values("QMAKE_PREFIX_SHLIB").first() + stub + Option::libtool_ext)) {
+ (*it) = libdirs[dep_i].real() + Option::dir_sep + project->values("QMAKE_PREFIX_SHLIB").first() + stub + Option::libtool_ext;
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+QString linkLib(const QString &file, const QString &libName) {
+ QString ret;
+ QRegExp reg("^.*lib(" + QRegExp::escape(libName) + "[^./=]*).*$");
+ if(reg.exactMatch(file))
+ ret = "-l" + reg.cap(1);
+ return ret;
+}
+
+void
+UnixMakefileGenerator::processPrlFiles()
+{
+ QList<QMakeLocalFileName> libdirs, frameworkdirs;
+ frameworkdirs.append(QMakeLocalFileName("/System/Library/Frameworks"));
+ const QString lflags[] = { "QMAKE_LIBDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS", "QMAKE_LFLAGS", "QMAKE_LIBS", QString() };
+ for(int i = 0; !lflags[i].isNull(); i++) {
+ QStringList &l = project->values(lflags[i]);
+ for(int lit = 0; lit < l.size(); ++lit) {
+ QString opt = l.at(lit).trimmed();
+ if(opt.startsWith("-")) {
+ if(opt.startsWith("-L")) {
+ QMakeLocalFileName l(opt.right(opt.length()-2));
+ if(!libdirs.contains(l))
+ libdirs.append(l);
+ } else if(opt.startsWith("-l")) {
+ QString lib = opt.right(opt.length() - 2);
+ for(int dep_i = 0; dep_i < libdirs.size(); ++dep_i) {
+ const QMakeLocalFileName &lfn = libdirs[dep_i];
+ if(!project->isActiveConfig("compile_libtool")) { //give them the .libs..
+ QString la = lfn.local() + Option::dir_sep + project->values("QMAKE_PREFIX_SHLIB").first() + lib + Option::libtool_ext;
+ if(exists(la) && QFile::exists(lfn.local() + Option::dir_sep + ".libs")) {
+ QString dot_libs = lfn.real() + Option::dir_sep + ".libs";
+ l.append("-L" + dot_libs);
+ libdirs.append(QMakeLocalFileName(dot_libs));
+ }
+ }
+
+ QString prl = lfn.local() + Option::dir_sep + project->values("QMAKE_PREFIX_SHLIB").first() + lib;
+ if(!project->isEmpty("QMAKE_" + lib.toUpper() + "_SUFFIX"))
+ prl += project->first("QMAKE_" + lib.toUpper() + "_SUFFIX");
+ if(processPrlFile(prl)) {
+ if(prl.startsWith(lfn.local()))
+ prl.replace(0, lfn.local().length(), lfn.real());
+ opt = linkLib(prl, lib);
+ break;
+ }
+ }
+ } else if(Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-F")) {
+ QMakeLocalFileName f(opt.right(opt.length()-2));
+ if(!frameworkdirs.contains(f))
+ frameworkdirs.append(f);
+ } else if(Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-framework")) {
+ if(opt.length() > 11)
+ opt = opt.mid(11);
+ else
+ opt = l.at(++lit);
+ opt = opt.trimmed();
+ const QList<QMakeLocalFileName> dirs = frameworkdirs + libdirs;
+ for(int dep_i = 0; dep_i < dirs.size(); ++dep_i) {
+ QString prl = dirs[dep_i].local() + "/" + opt + ".framework/" + opt + Option::prl_ext;
+ if(processPrlFile(prl))
+ break;
+ }
+ }
+ } else if(!opt.isNull()) {
+ QString lib = opt;
+ processPrlFile(lib);
+#if 0
+ if(ret)
+ opt = linkLib(lib, "");
+#endif
+ if(!opt.isEmpty())
+ l.replaceInStrings(lib, opt);
+ }
+
+ QStringList &prl_libs = project->values("QMAKE_CURRENT_PRL_LIBS");
+ if(!prl_libs.isEmpty()) {
+ for(int prl = 0; prl < prl_libs.size(); ++prl)
+ l.insert(lit+prl+1, prl_libs.at(prl));
+ prl_libs.clear();
+ }
+ }
+
+ //merge them into a logical order
+ if(!project->isActiveConfig("no_smart_library_merge") && !project->isActiveConfig("no_lflags_merge")) {
+ QHash<QString, QStringList> lflags;
+ for(int lit = 0; lit < l.size(); ++lit) {
+ QString arch("default");
+ QString opt = l.at(lit).trimmed();
+ if(opt.startsWith("-")) {
+ if (Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-Xarch")) {
+ if (opt.length() > 7) {
+ arch = opt.mid(7);
+ opt = l.at(++lit);
+ }
+ }
+
+ if(opt.startsWith("-L") ||
+ (Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-F"))) {
+ if(!lflags[arch].contains(opt))
+ lflags[arch].append(opt);
+ } else if(opt.startsWith("-l") || opt == "-pthread") {
+ // Make sure we keep the dependency-order of libraries
+ if (lflags[arch].contains(opt))
+ lflags[arch].removeAll(opt);
+ lflags[arch].append(opt);
+ } else if(Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-framework")) {
+ if(opt.length() > 11)
+ opt = opt.mid(11);
+ else {
+ opt = l.at(++lit);
+ if (Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-Xarch"))
+ opt = l.at(++lit); // The user has done the right thing and prefixed each part
+ }
+ bool found = false;
+ for(int x = 0; x < lflags[arch].size(); ++x) {
+ QString xf = lflags[arch].at(x);
+ if(xf.startsWith("-framework")) {
+ QString framework;
+ if(xf.length() > 11)
+ framework = xf.mid(11);
+ else
+ framework = lflags[arch].at(++x);
+ if(framework == opt) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if(!found) {
+ lflags[arch].append("-framework");
+ lflags[arch].append(opt);
+ }
+ } else {
+ lflags[arch].append(opt);
+ }
+ } else if(!opt.isNull()) {
+ if(!lflags[arch].contains(opt))
+ lflags[arch].append(opt);
+ }
+ }
+
+ l = lflags.take("default");
+
+ // Process architecture specific options (Xarch)
+ QHash<QString, QStringList>::const_iterator archIterator = lflags.constBegin();
+ while (archIterator != lflags.constEnd()) {
+ const QStringList archOptions = archIterator.value();
+ for (int i = 0; i < archOptions.size(); ++i) {
+ l.append(QLatin1String("-Xarch_") + archIterator.key());
+ l.append(archOptions.at(i));
+ }
+ ++archIterator;
+ }
+ }
+ }
+}
+
+QString
+UnixMakefileGenerator::defaultInstall(const QString &t)
+{
+ if(t != "target" || project->first("TEMPLATE") == "subdirs")
+ return QString();
+
+ bool bundle = false;
+ const QString root = "$(INSTALL_ROOT)";
+ QStringList &uninst = project->values(t + ".uninstall");
+ QString ret, destdir=project->first("DESTDIR");
+ QString targetdir = Option::fixPathToTargetOS(project->first("target.path"), false);
+ if(!destdir.isEmpty() && destdir.right(1) != Option::dir_sep)
+ destdir += Option::dir_sep;
+ targetdir = fileFixify(targetdir, FileFixifyAbsolute);
+ if(targetdir.right(1) != Option::dir_sep)
+ targetdir += Option::dir_sep;
+
+ QStringList links;
+ QString target="$(TARGET)";
+ QStringList &targets = project->values(t + ".targets");
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ target = project->first("QMAKE_BUNDLE");
+ bundle = true;
+ } else if(project->first("TEMPLATE") == "app") {
+ target = "$(QMAKE_TARGET)";
+ } else if(project->first("TEMPLATE") == "lib") {
+ if(project->isEmpty("QMAKE_CYGWIN_SHLIB")) {
+ if(!project->isActiveConfig("staticlib") && !project->isActiveConfig("plugin")) {
+ if(project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ links << "$(TARGET0)" << "$(TARGET1)" << "$(TARGET2)";
+ } else {
+ links << "$(TARGET0)";
+ }
+ }
+ }
+ }
+ for(int i = 0; i < targets.size(); ++i) {
+ QString src = targets.at(i),
+ dst = filePrefixRoot(root, targetdir + src.section('/', -1));
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += "-$(INSTALL_FILE) \"" + src + "\" \"" + dst + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst + "\"");
+ }
+
+ if(!bundle && project->isActiveConfig("compile_libtool")) {
+ QString src_targ = target;
+ if(src_targ == "$(TARGET)")
+ src_targ = "$(TARGETL)";
+ QString dst_dir = fileFixify(targetdir, FileFixifyAbsolute);
+ if(QDir::isRelativePath(dst_dir))
+ dst_dir = Option::fixPathToTargetOS(Option::output_dir + Option::dir_sep + dst_dir);
+ ret = "-$(LIBTOOL) --mode=install cp \"" + src_targ + "\" \"" + filePrefixRoot(root, dst_dir) + "\"";
+ uninst.append("-$(LIBTOOL) --mode=uninstall \"" + src_targ + "\"");
+ } else {
+ QString src_targ = target;
+ if(!destdir.isEmpty())
+ src_targ = Option::fixPathToTargetOS(destdir + target, false);
+ QString dst_targ = filePrefixRoot(root, fileFixify(targetdir + target, FileFixifyAbsolute));
+ if(bundle) {
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += "$(DEL_FILE) -r \"" + dst_targ + "\"\n\t";
+ }
+ if(!ret.isEmpty())
+ ret += "\n\t";
+
+ QString copy_cmd("-");
+ if (bundle)
+ copy_cmd += "$(INSTALL_DIR)";
+ else if (project->first("TEMPLATE") == "lib" && project->isActiveConfig("staticlib"))
+ copy_cmd += "$(INSTALL_FILE)";
+ else
+ copy_cmd += "$(INSTALL_PROGRAM)";
+ copy_cmd += " \"" + src_targ + "\" \"" + dst_targ + "\"";
+ if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib")
+ && project->values(t + ".CONFIG").indexOf("fix_rpath") != -1) {
+ if(!project->isEmpty("QMAKE_FIX_RPATH")) {
+ ret += copy_cmd;
+ ret += "\n\t-" + var("QMAKE_FIX_RPATH") + " \"" +
+ dst_targ + "\" \"" + dst_targ + "\"";
+ } else if(!project->isEmpty("QMAKE_LFLAGS_RPATH")) {
+ ret += "-$(LINK) $(LFLAGS) " + var("QMAKE_LFLAGS_RPATH") + targetdir + " -o \"" +
+ dst_targ + "\" $(OBJECTS) $(LIBS) $(OBJCOMP)";
+ } else {
+ ret += copy_cmd;
+ }
+ } else {
+ ret += copy_cmd;
+ }
+
+ if(project->first("TEMPLATE") == "lib" && project->isActiveConfig("staticlib")) {
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ ret += QString("\n\t$(RANLIB) \"") + dst_targ + "\"";
+ } else if(!project->isActiveConfig("debug") && !project->isActiveConfig("nostrip") && !project->isEmpty("QMAKE_STRIP")) {
+ ret += "\n\t-$(STRIP)";
+ if(project->first("TEMPLATE") == "lib" && !project->isEmpty("QMAKE_STRIPFLAGS_LIB"))
+ ret += " " + var("QMAKE_STRIPFLAGS_LIB");
+ else if(project->first("TEMPLATE") == "app" && !project->isEmpty("QMAKE_STRIPFLAGS_APP"))
+ ret += " " + var("QMAKE_STRIPFLAGS_APP");
+ if(bundle)
+ ret = " \"" + dst_targ + "/Contents/MacOS/$(QMAKE_TARGET)\"";
+ else
+ ret += " \"" + dst_targ + "\"";
+ }
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ if(bundle)
+ uninst.append("-$(DEL_FILE) -r \"" + dst_targ + "\"");
+ else
+ uninst.append("-$(DEL_FILE) \"" + dst_targ + "\"");
+ if(!links.isEmpty()) {
+ for(int i = 0; i < links.size(); ++i) {
+ if(Option::target_mode == Option::TARG_UNIX_MODE ||
+ Option::target_mode == Option::TARG_MACX_MODE) {
+ QString link = Option::fixPathToTargetOS(destdir + links[i], false);
+ int lslash = link.lastIndexOf(Option::dir_sep);
+ if(lslash != -1)
+ link = link.right(link.length() - (lslash + 1));
+ QString dst_link = filePrefixRoot(root, fileFixify(targetdir + link, FileFixifyAbsolute));
+ ret += "\n\t-$(SYMLINK) \"$(TARGET)\" \"" + dst_link + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_link + "\"");
+ }
+ }
+ }
+ }
+ if(project->first("TEMPLATE") == "lib") {
+ QStringList types;
+ types << "prl" << "libtool" << "pkgconfig";
+ for(int i = 0; i < types.size(); ++i) {
+ const QString type = types.at(i);
+ QString meta;
+ if(type == "prl" && project->isActiveConfig("create_prl") && !project->isActiveConfig("no_install_prl") &&
+ !project->isEmpty("QMAKE_INTERNAL_PRL_FILE"))
+ meta = prlFileName(false);
+ if(type == "libtool" && project->isActiveConfig("create_libtool") && !project->isActiveConfig("compile_libtool"))
+ meta = libtoolFileName(false);
+ if(type == "pkgconfig" && project->isActiveConfig("create_pc"))
+ meta = pkgConfigFileName(false);
+ if(!meta.isEmpty()) {
+ QString src_meta = meta;
+ if(!destdir.isEmpty())
+ src_meta = Option::fixPathToTargetOS(destdir + meta, false);
+ QString dst_meta = filePrefixRoot(root, fileFixify(targetdir + meta, FileFixifyAbsolute));
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_meta + "\"");
+ const QString replace_rule("QMAKE_" + type.toUpper() + "_INSTALL_REPLACE");
+ const QString dst_meta_dir = fileInfo(dst_meta).path();
+ if(!dst_meta_dir.isEmpty()) {
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += mkdir_p_asstring(dst_meta_dir, true);
+ }
+ QString install_meta = "$(INSTALL_FILE) \"" + src_meta + "\" \"" + dst_meta + "\"";
+ if(project->isEmpty(replace_rule) || project->isActiveConfig("no_sed_meta_install")) {
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += "-" + install_meta;
+ } else {
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += "-$(SED)";
+ QStringList replace_rules = project->values(replace_rule);
+ for(int r = 0; r < replace_rules.size(); ++r) {
+ const QString match = project->first(replace_rules.at(r) + ".match"),
+ replace = project->first(replace_rules.at(r) + ".replace");
+ if(!match.isEmpty() /*&& match != replace*/)
+ ret += " -e \"s," + match + "," + replace + ",g\"";
+ }
+ ret += " \"" + src_meta + "\" >\"" + dst_meta + "\"";
+ //ret += " || " + install_meta;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+QString
+UnixMakefileGenerator::escapeFilePath(const QString &path) const
+{
+ QString ret = path;
+ if(!ret.isEmpty()) {
+ ret = unescapeFilePath(ret).replace(QLatin1Char(' '), QLatin1String("\\ "));
+ debug_msg(2, "EscapeFilePath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
+ }
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/unix/unixmake.h b/qmake/generators/unix/unixmake.h
new file mode 100644
index 0000000000..acbe8c4a6b
--- /dev/null
+++ b/qmake/generators/unix/unixmake.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 UNIXMAKE_H
+#define UNIXMAKE_H
+
+#include "makefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class UnixMakefileGenerator : public MakefileGenerator
+{
+ bool init_flag, include_deps;
+ QString libtoolFileName(bool fixify=true);
+ void writeLibtoolFile(); // for libtool
+ void writePrlFile(QTextStream &);
+
+public:
+ UnixMakefileGenerator();
+ ~UnixMakefileGenerator();
+
+protected:
+ virtual bool doPrecompiledHeaders() const { return project->isActiveConfig("precompile_header"); }
+ virtual bool doDepends() const { return !include_deps && !Option::mkfile::do_stub_makefile && MakefileGenerator::doDepends(); }
+ virtual QString defaultInstall(const QString &);
+ virtual void processPrlVariable(const QString &, const QStringList &);
+ virtual void processPrlFiles();
+
+ virtual bool findLibraries();
+ virtual QString escapeFilePath(const QString &path) const;
+ virtual QStringList &findDependencies(const QString &);
+ virtual void init();
+
+ void writeMakeParts(QTextStream &);
+ bool writeMakefile(QTextStream &);
+
+private:
+ void init2();
+};
+
+inline UnixMakefileGenerator::~UnixMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // UNIXMAKE_H
diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp
new file mode 100644
index 0000000000..9f144929ed
--- /dev/null
+++ b/qmake/generators/unix/unixmake2.cpp
@@ -0,0 +1,1352 @@
+/****************************************************************************
+**
+** 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 "meta.h"
+#include <qregexp.h>
+#include <qbytearray.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qdatetime.h>
+#include <qdebug.h>
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+UnixMakefileGenerator::UnixMakefileGenerator() : MakefileGenerator(), init_flag(false), include_deps(false)
+{
+
+}
+
+void
+UnixMakefileGenerator::writePrlFile(QTextStream &t)
+{
+ MakefileGenerator::writePrlFile(t);
+ // libtool support
+
+ if(project->isActiveConfig("create_libtool") && project->first("TEMPLATE") == "lib") { //write .la
+ if(project->isActiveConfig("compile_libtool"))
+ warn_msg(WarnLogic, "create_libtool specified with compile_libtool can lead to conflicting .la\n"
+ "formats, create_libtool has been disabled\n");
+ else
+ writeLibtoolFile();
+ }
+ // pkg-config support
+ if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib")
+ writePkgConfigFile();
+}
+
+bool
+UnixMakefileGenerator::writeMakefile(QTextStream &t)
+{
+
+ writeHeader(t);
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ 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 << " ";
+ t << "first all clean install distclean uninstall qmake_all:" << "\n\t"
+ << "@echo \"Some of the required modules ("
+ << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
+ << "@echo \"Skipped.\"" << endl << endl;
+ writeMakeQmake(t);
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << "FORCE:" << endl << endl;
+ return true;
+ }
+
+ if (project->values("TEMPLATE").first() == "app" ||
+ project->values("TEMPLATE").first() == "lib") {
+ if(Option::mkfile::do_stub_makefile && MakefileGenerator::writeStubMakefile(t))
+ return true;
+ writeMakeParts(t);
+ return MakefileGenerator::writeMakefile(t);
+ } else if(project->values("TEMPLATE").first() == "subdirs") {
+ MakefileGenerator::writeSubDirs(t);
+ return true;
+ }
+ return false;
+}
+
+void
+UnixMakefileGenerator::writeMakeParts(QTextStream &t)
+{
+ QString deps = fileFixify(Option::output.fileName()), target_deps, prl;
+ bool do_incremental = (project->isActiveConfig("incremental") &&
+ !project->values("QMAKE_INCREMENTAL").isEmpty() &&
+ (!project->values("QMAKE_APP_FLAG").isEmpty() ||
+ (!project->isActiveConfig("staticlib")))),
+ src_incremental=false;
+
+ t << "####### Compiler, tools and options" << endl << endl;
+ t << "CC = " << var("QMAKE_CC") << endl;
+ t << "CXX = " << var("QMAKE_CXX") << endl;
+ t << "DEFINES = "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << varGlue("DEFINES","-D"," -D","") << endl;
+ t << "CFLAGS = " << var("QMAKE_CFLAGS") << " $(DEFINES)" << endl;
+ t << "CXXFLAGS = " << var("QMAKE_CXXFLAGS") << " $(DEFINES)" << endl;
+ t << "INCPATH = " << "-I" << specdir();
+ if(!project->isActiveConfig("no_include_pwd")) {
+ QString pwd = escapeFilePath(fileFixify(qmake_getpwd()));
+ if(pwd.isEmpty())
+ pwd = ".";
+ t << " -I" << pwd;
+ }
+ {
+ const QStringList &incs = project->values("INCLUDEPATH");
+ for(int i = 0; i < incs.size(); ++i) {
+ QString inc = escapeFilePath(incs.at(i));
+ if(!inc.isEmpty())
+ t << " " << "-I" << inc;
+ }
+ }
+ if(!project->isEmpty("QMAKE_FRAMEWORKPATH_FLAGS"))
+ t << " " << var("QMAKE_FRAMEWORKPATH_FLAGS");
+ t << endl;
+
+ if(!project->isActiveConfig("staticlib")) {
+ t << "LINK = " << var("QMAKE_LINK") << endl;
+ t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl;
+ t << "LIBS = " << "$(SUBLIBS) " << var("QMAKE_FRAMEWORKPATH_FLAGS") << " "
+ << var("QMAKE_LIBDIR_FLAGS") << " " << var("QMAKE_LIBS") << " " << var("QMAKE_LIBS_PRIVATE") << endl;
+ }
+
+ t << "AR = " << var("QMAKE_AR") << endl;
+ t << "RANLIB = " << var("QMAKE_RANLIB") << endl;
+ t << "QMAKE = " << var("QMAKE_QMAKE") << endl;
+ t << "TAR = " << var("QMAKE_TAR") << endl;
+ t << "COMPRESS = " << var("QMAKE_GZIP") << endl;
+ if(project->isActiveConfig("compile_libtool"))
+ t << "LIBTOOL = " << var("QMAKE_LIBTOOL") << endl;
+ t << "COPY = " << var("QMAKE_COPY") << endl;
+ t << "SED = " << var("QMAKE_STREAM_EDITOR") << endl;
+ t << "COPY_FILE = " << var("QMAKE_COPY_FILE") << endl;
+ t << "COPY_DIR = " << var("QMAKE_COPY_DIR") << endl;
+ t << "STRIP = " << var("QMAKE_STRIP") << endl;
+ t << "INSTALL_FILE = " << var("QMAKE_INSTALL_FILE") << endl;
+ t << "INSTALL_DIR = " << var("QMAKE_INSTALL_DIR") << endl;
+ t << "INSTALL_PROGRAM = " << var("QMAKE_INSTALL_PROGRAM") << 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;
+ if(!project->isEmpty("QMAKE_MACOSX_DEPLOYMENT_TARGET"))
+ t << "export MACOSX_DEPLOYMENT_TARGET = " //exported to children processes
+ << project->first("QMAKE_MACOSX_DEPLOYMENT_TARGET") << endl;
+
+ if (!project->isEmpty("QMAKE_SYMBIAN_SHLIB")) {
+ t << "vpath %.dso " << project->values("QMAKE_LIBDIR").join(":") << endl;
+ t << "vpath %.lib " << project->values("QMAKE_LIBDIR").join(":") << endl;
+ }
+
+ t << endl;
+
+ t << "####### Output directory" << endl << endl;
+ if (! project->values("OBJECTS_DIR").isEmpty())
+ t << "OBJECTS_DIR = " << var("OBJECTS_DIR") << endl;
+ else
+ t << "OBJECTS_DIR = ./" << endl;
+ t << endl;
+
+ /* files */
+ t << "####### Files" << endl << endl;
+ t << "SOURCES = " << valList(escapeFilePaths(project->values("SOURCES"))) << " "
+ << valList(escapeFilePaths(project->values("GENERATED_SOURCES"))) << endl;
+ if(do_incremental) {
+ QStringList &objs = project->values("OBJECTS"), &incrs = project->values("QMAKE_INCREMENTAL"), incrs_out;
+ t << "OBJECTS = ";
+ for(QStringList::Iterator objit = objs.begin(); objit != objs.end(); ++objit) {
+ bool increment = false;
+ for(QStringList::Iterator incrit = incrs.begin(); incrit != incrs.end(); ++incrit) {
+ if((*objit).indexOf(QRegExp((*incrit), Qt::CaseSensitive,
+ QRegExp::Wildcard)) != -1) {
+ increment = true;
+ incrs_out.append((*objit));
+ break;
+ }
+ }
+ if(!increment)
+ t << "\\\n\t\t" << (*objit);
+ }
+ if(incrs_out.count() == objs.count()) { //we just switched places, no real incrementals to be done!
+ t << escapeFilePaths(incrs_out).join(" \\\n\t\t") << endl;
+ } else if(!incrs_out.count()) {
+ t << endl;
+ } else {
+ src_incremental = true;
+ t << endl;
+ t << "INCREMENTAL_OBJECTS = " << escapeFilePaths(incrs_out).join(" \\\n\t\t") << endl;
+ }
+ } else {
+ t << "OBJECTS = " << valList(escapeFilePaths(project->values("OBJECTS"))) << endl;
+ }
+ if(do_incremental && !src_incremental)
+ do_incremental = false;
+ t << "DIST = " << valList(fileFixify(project->values("DISTFILES"))) << endl;
+ t << "QMAKE_TARGET = " << var("QMAKE_ORIG_TARGET") << endl;
+ t << "DESTDIR = " << var("DESTDIR") << endl;
+ if(project->isActiveConfig("compile_libtool"))
+ t << "TARGETL = " << var("TARGET_la") << endl;
+ t << "TARGET = " << escapeFilePath(var("TARGET")) << endl;
+ if(project->isActiveConfig("plugin")) {
+ t << "TARGETD = " << escapeFilePath(var("TARGET")) << endl;
+ } else if(!project->isActiveConfig("staticlib") && project->values("QMAKE_APP_FLAG").isEmpty()) {
+ t << "TARGETA = " << escapeFilePath(var("TARGETA")) << endl;
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ t << "TARGETD = " << escapeFilePath(var("TARGET_x.y")) << endl;
+ t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl;
+ } else if(!project->isEmpty("QMAKE_SYMBIAN_SHLIB")) {
+ t << "TARGETD = " << escapeFilePath(var("TARGET")) << endl;
+ } else if(project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ t << "TARGETD = " << escapeFilePath(var("TARGET_x.y.z")) << endl;
+ t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl;
+ t << "TARGET1 = " << escapeFilePath(var("TARGET_x")) << endl;
+ t << "TARGET2 = " << escapeFilePath(var("TARGET_x.y")) << endl;
+ } else {
+ t << "TARGETD = " << escapeFilePath(var("TARGET_x")) << endl;
+ t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl;
+ }
+ }
+ writeExtraCompilerVariables(t);
+ writeExtraVariables(t);
+ t << endl;
+
+ // blasted includes
+ QStringList &qeui = project->values("QMAKE_EXTRA_INCLUDES");
+ QStringList::Iterator it;
+ for(it = qeui.begin(); it != qeui.end(); ++it)
+ t << "include " << (*it) << endl;
+
+ /* rules */
+ t << "first: all" << endl;
+ t << "####### Implicit rules" << endl << endl;
+ t << ".SUFFIXES: " << Option::obj_ext;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << " " << (*cit);
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << " " << (*cppit);
+ t << endl << endl;
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << (*cppit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CXX_IMP") << endl << endl;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << (*cit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CC_IMP") << endl << endl;
+
+ if(include_deps) {
+ QString cmd=var("QMAKE_CFLAGS_DEPS") + " ";
+ cmd += varGlue("DEFINES","-D"," -D","") + varGlue("PRL_EXPORT_DEFINES"," -D"," -D","");
+ if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
+ cmd += " -I" + project->first("QMAKE_ABSOLUTE_SOURCE_PATH") + " ";
+ cmd += " $(INCPATH) " + varGlue("DEPENDPATH", "-I", " -I", "");
+ QString odir;
+ if(!project->values("OBJECTS_DIR").isEmpty())
+ odir = project->first("OBJECTS_DIR");
+ t << "###### Dependencies" << endl << endl;
+ t << odir << ".deps/%.d: %.cpp\n\t";
+ if(project->isActiveConfig("echo_depend_creation"))
+ t << "@echo Creating depend for $<" << "\n\t";
+ t << mkdir_p_asstring("$(@D)") << "\n\t"
+ << "@$(CXX) " << cmd << " $< | sed \"s,^\\($(*F).o\\):," << odir << "\\1:,g\" >$@" << endl << endl;
+
+ t << odir << ".deps/%.d: %.c\n\t";
+ if(project->isActiveConfig("echo_depend_creation"))
+ t << "@echo Creating depend for $<" << "\n\t";
+ t << mkdir_p_asstring("$(@D)") << "\n\t"
+ << "@$(CC) " << cmd << " $< | sed \"s,^\\($(*F).o\\):," << odir << "\\1:,g\" >$@" << endl << endl;
+
+ QString src[] = { "SOURCES", "GENERATED_SOURCES", QString() };
+ for(int x = 0; !src[x].isNull(); x++) {
+ QStringList &l = project->values(src[x]);
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ if(!(*it).isEmpty()) {
+ QString d_file;
+ for(QStringList::Iterator cit = Option::c_ext.begin();
+ cit != Option::c_ext.end(); ++cit) {
+ if((*it).endsWith((*cit))) {
+ d_file = (*it).left((*it).length() - (*cit).length());
+ break;
+ }
+ }
+ if(d_file.isEmpty()) {
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin();
+ cppit != Option::cpp_ext.end(); ++cppit) {
+ if((*it).endsWith((*cppit))) {
+ d_file = (*it).left((*it).length() - (*cppit).length());
+ break;
+ }
+ }
+ }
+ if(!d_file.isEmpty()) {
+ d_file = odir + ".deps/" + d_file + ".d";
+ QStringList deps = findDependencies((*it)).filter(QRegExp(Option::cpp_moc_ext + "$"));
+ if(!deps.isEmpty())
+ t << d_file << ": " << deps.join(" ") << endl;
+ t << "-include " << d_file << endl;
+ project->values("QMAKE_DISTCLEAN") += d_file;
+ }
+ }
+ }
+ }
+ }
+
+ t << "####### Build rules" << endl << endl;
+ if(!project->values("SUBLIBS").isEmpty()) {
+ QString libdir = "tmp/";
+ if(!project->isEmpty("SUBLIBS_DIR"))
+ libdir = project->first("SUBLIBS_DIR");
+ t << "SUBLIBS = ";
+ QStringList &l = project->values("SUBLIBS");
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it)
+ t << libdir << project->first("QMAKE_PREFIX_STATICLIB") << (*it) << "."
+ << project->first("QMAKE_EXTENSION_STATICLIB") << " ";
+ t << endl << endl;
+ }
+ if(project->isActiveConfig("depend_prl") && !project->isEmpty("QMAKE_PRL_INTERNAL_FILES")) {
+ QStringList &l = project->values("QMAKE_PRL_INTERNAL_FILES");
+ QStringList::Iterator it;
+ for(it = l.begin(); it != l.end(); ++it) {
+ QMakeMetaInfo libinfo;
+ if(libinfo.readLib((*it)) && !libinfo.isEmpty("QMAKE_PRL_BUILD_DIR")) {
+ QString dir;
+ int slsh = (*it).lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ dir = (*it).left(slsh + 1);
+ QString targ = dir + libinfo.first("QMAKE_PRL_TARGET");
+ target_deps += " " + targ;
+ t << targ << ":" << "\n\t"
+ << "@echo \"Creating '" << targ << "'\"" << "\n\t"
+ << "(cd " << libinfo.first("QMAKE_PRL_BUILD_DIR") << ";"
+ << "$(MAKE))" << endl;
+ }
+ }
+ }
+ if(!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ QString destdir = project->first("DESTDIR");
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ destdir += project->first("QMAKE_BUNDLE") + bundle_loc;
+ }
+ if(do_incremental) {
+ //incremental target
+ QString incr_target = var("TARGET") + "_incremental";
+ if(incr_target.indexOf(Option::dir_sep) != -1)
+ incr_target = incr_target.right(incr_target.length() -
+ (incr_target.lastIndexOf(Option::dir_sep) + 1));
+ QString incr_deps, incr_objs;
+ if(project->first("QMAKE_INCREMENTAL_STYLE") == "ld") {
+ QString incr_target_dir = var("OBJECTS_DIR") + incr_target + Option::obj_ext;
+ //actual target
+ t << incr_target_dir << ": $(OBJECTS)" << "\n\t"
+ << "ld -r -o "<< incr_target_dir << " $(OBJECTS)" << endl;
+ //communicated below
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(INCREMENTAL_OBJECTS)";
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += incr_target_dir;
+ } else {
+ //actual target
+ QString incr_target_dir = var("DESTDIR") + "lib" + incr_target + "." +
+ project->values("QMAKE_EXTENSION_SHLIB").first();
+ QString incr_lflags = var("QMAKE_LFLAGS_SHLIB") + " ";
+ if(project->isActiveConfig("debug"))
+ incr_lflags += var("QMAKE_LFLAGS_DEBUG");
+ else
+ incr_lflags += var("QMAKE_LFLAGS_RELEASE");
+ t << incr_target_dir << ": $(INCREMENTAL_OBJECTS)" << "\n\t";
+ if(!destdir.isEmpty())
+ t << "\n\t" << mkdir_p_asstring(destdir) << "\n\t";
+ t << "$(LINK) " << incr_lflags << " -o "<< incr_target_dir <<
+ " $(INCREMENTAL_OBJECTS)" << endl;
+ //communicated below
+ if(!destdir.isEmpty()) {
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += "-L" + destdir;
+ } else {
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += "-L" + qmake_getpwd();
+ }
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += " -l" + incr_target;
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(OBJECTS)";
+ }
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << "$(TARGET)"
+ << endl << endl;
+
+ //real target
+ t << var("TARGET") << ": " << var("PRE_TARGETDEPS") << " " << incr_deps << " " << target_deps
+ << " " << var("POST_TARGETDEPS") << "\n\t";
+ if(!destdir.isEmpty())
+ t << "\n\t" << mkdir_p_asstring(destdir) << "\n\t";
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << var("QMAKE_PRE_LINK") << "\n\t";
+ t << "$(LINK) $(LFLAGS) -o $(TARGET) " << incr_deps << " " << incr_objs << " $(OBJCOMP) $(LIBS)";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else {
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << "$(TARGET)"
+ << endl << endl;
+
+ t << "$(TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) "
+ << target_deps << " " << var("POST_TARGETDEPS") << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << var("QMAKE_PRE_LINK") << "\n\t";
+ t << "$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ }
+ } else if(!project->isActiveConfig("staticlib")) {
+ QString destdir = unescapeFilePath(project->first("DESTDIR")), incr_deps;
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ destdir += project->first("QMAKE_BUNDLE") + bundle_loc;
+ }
+ destdir = escapeFilePath(destdir);
+
+ if(do_incremental) {
+ QString s_ext = project->values("QMAKE_EXTENSION_SHLIB").first();
+ QString incr_target = var("QMAKE_ORIG_TARGET").replace(
+ QRegExp("\\." + s_ext), "").replace(QRegExp("^lib"), "") + "_incremental";
+ if(incr_target.indexOf(Option::dir_sep) != -1)
+ incr_target = incr_target.right(incr_target.length() -
+ (incr_target.lastIndexOf(Option::dir_sep) + 1));
+ incr_target = escapeFilePath(incr_target);
+
+ if(project->first("QMAKE_INCREMENTAL_STYLE") == "ld") {
+ QString incr_target_dir = escapeFilePath(var("OBJECTS_DIR") + incr_target + Option::obj_ext);
+ //actual target
+ const QString link_deps = "$(OBJECTS) ";
+ t << incr_target_dir << ": " << link_deps << "\n\t"
+ << "ld -r -o " << incr_target_dir << " " << link_deps << endl;
+ //communicated below
+ QStringList &cmd = project->values("QMAKE_LINK_SHLIB_CMD");
+ cmd.first().replace("$(OBJECTS) ", "$(INCREMENTAL_OBJECTS)"); //ick
+ cmd.append(incr_target_dir);
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(INCREMENTAL_OBJECTS)";
+ } else {
+ //actual target
+ QString incr_target_dir = escapeFilePath(destdir + "lib" + incr_target + "." + s_ext);
+ QString incr_lflags = var("QMAKE_LFLAGS_SHLIB") + " ";
+ if(!project->isEmpty("QMAKE_LFLAGS_INCREMENTAL"))
+ incr_lflags += var("QMAKE_LFLAGS_INCREMENTAL") + " ";
+ if(project->isActiveConfig("debug"))
+ incr_lflags += var("QMAKE_LFLAGS_DEBUG");
+ else
+ incr_lflags += var("QMAKE_LFLAGS_RELEASE");
+ t << incr_target_dir << ": $(INCREMENTAL_OBJECTS)" << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "$(LINK) " << incr_lflags << " -o "<< incr_target_dir <<
+ " $(INCREMENTAL_OBJECTS)" << endl;
+ //communicated below
+ QStringList &cmd = project->values("QMAKE_LINK_SHLIB_CMD");
+ if(!destdir.isEmpty())
+ cmd.append(" -L" + destdir);
+ cmd.append(" -l" + incr_target);
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(OBJECTS)";
+ }
+
+ t << "all: " << " " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ")
+ << " " << destdir << "$(TARGET)" << endl << endl;
+
+ //real target
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS") << " "
+ << incr_deps << " $(SUBLIBS) " << target_deps << " " << var("POST_TARGETDEPS");
+ } else {
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << " " <<
+ destdir << "$(TARGET)" << endl << endl;
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS")
+ << " $(OBJECTS) $(SUBLIBS) $(OBJCOMP) " << target_deps
+ << " " << var("POST_TARGETDEPS");
+ }
+ if(!destdir.isEmpty())
+ t << "\n\t" << mkdir_p_asstring(destdir);
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << "\n\t" << var("QMAKE_PRE_LINK");
+
+ if(project->isActiveConfig("compile_libtool")) {
+ t << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD");
+ } else if(project->isActiveConfig("plugin")) {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET)" << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD");
+ if(!destdir.isEmpty())
+ t << "\n\t"
+ << "-$(MOVE) $(TARGET) " << destdir;
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else if(!project->isEmpty("QMAKE_BUNDLE")) {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET) $(TARGET0) $(DESTDIR)$(TARGET0)" << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD") << "\n\t"
+ << mkdir_p_asstring("\"`dirname $(DESTDIR)$(TARGETD)`\"", false) << "\n\t"
+ << "-$(MOVE) $(TARGET) $(DESTDIR)$(TARGETD)" << "\n\t"
+ << mkdir_p_asstring("\"`dirname $(DESTDIR)$(TARGET0)`\"", false) << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," "," Versions/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") +
+ "/$(TARGET) $(DESTDIR)$(TARGET0)") << "\n\t"
+ << "-$(DEL_FILE) " << destdir << "Versions/Current" << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," ", " " + project->first("QMAKE_FRAMEWORK_VERSION") +
+ " " + destdir + "Versions/Current") << "\n\t";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else if(!project->isEmpty("QMAKE_SYMBIAN_SHLIB")) {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET)" << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD");
+ if(!destdir.isEmpty())
+ t << "\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t"
+ << "-$(MOVE) $(TARGET) " << destdir;
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else if(project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2)" << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD") << "\n\t";
+ t << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET0)") << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET1)") << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET2)");
+ if(!destdir.isEmpty())
+ t << "\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET0)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET1)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET2)\n\t"
+ << "-$(MOVE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2) " << destdir;
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET) $(TARGET0)" << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD") << "\n\t";
+ t << varGlue("QMAKE_LN_SHLIB",""," "," $(TARGET) $(TARGET0)");
+ if(!destdir.isEmpty())
+ t << "\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET0)\n\t"
+ << "-$(MOVE) $(TARGET) $(TARGET0) " << destdir;
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ }
+ t << endl << endl;
+
+ if (! project->isActiveConfig("plugin")) {
+ t << "staticlib: $(TARGETA)" << endl << endl;
+ t << "$(TARGETA): " << var("PRE_TARGETDEPS") << " $(OBJECTS) $(OBJCOMP)";
+ if(do_incremental)
+ t << " $(INCREMENTAL_OBJECTS)";
+ t << " " << var("POST_TARGETDEPS") << "\n\t"
+ << "-$(DEL_FILE) $(TARGETA) " << "\n\t"
+ << var("QMAKE_AR_CMD");
+ if(do_incremental)
+ t << " $(INCREMENTAL_OBJECTS)";
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ t << "\n\t" << "$(RANLIB) $(TARGETA)";
+ t << endl << endl;
+ }
+ } else {
+ QString destdir = project->first("DESTDIR");
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << destdir << "$(TARGET) "
+ << varGlue("QMAKE_AR_SUBLIBS", destdir, " " + destdir, "") << "\n\n"
+ << "staticlib: " << destdir << "$(TARGET)" << "\n\n";
+ if(project->isEmpty("QMAKE_AR_SUBLIBS")) {
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS")
+ << " $(OBJECTS) $(OBJCOMP) " << var("POST_TARGETDEPS") << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "-$(DEL_FILE) $(TARGET)" << "\n\t"
+ << var("QMAKE_AR_CMD") << "\n";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\t" << var("QMAKE_POST_LINK") << "\n";
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ t << "\t" << "$(RANLIB) $(TARGET)" << "\n";
+ if(!destdir.isEmpty())
+ t << "\t" << "-$(DEL_FILE) " << destdir << "$(TARGET)" << "\n"
+ << "\t" << "-$(MOVE) $(TARGET) " << destdir << "\n";
+ } else {
+ int max_files = project->first("QMAKE_MAX_FILES_PER_AR").toInt();
+ QStringList objs = project->values("OBJECTS") + project->values("OBJCOMP"),
+ libs = project->values("QMAKE_AR_SUBLIBS");
+ libs.prepend("$(TARGET)");
+ for(QStringList::Iterator libit = libs.begin(), objit = objs.begin();
+ libit != libs.end(); ++libit) {
+ QStringList build;
+ for(int cnt = 0; cnt < max_files && objit != objs.end(); ++objit, cnt++)
+ build << (*objit);
+ QString ar;
+ if((*libit) == "$(TARGET)") {
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS")
+ << " " << var("POST_TARGETDEPS") << valList(build) << "\n\t";
+ ar = project->values("QMAKE_AR_CMD").first();
+ ar = ar.replace("$(OBJECTS)", build.join(" "));
+ } else {
+ t << (*libit) << ": " << valList(build) << "\n\t";
+ ar = "$(AR) " + (*libit) + " " + build.join(" ");
+ }
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "-$(DEL_FILE) " << (*libit) << "\n\t"
+ << ar << "\n";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\t" << var("QMAKE_POST_LINK") << "\n";
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ t << "\t" << "$(RANLIB) " << (*libit) << "\n";
+ if(!destdir.isEmpty())
+ t << "\t" << "-$(DEL_FILE) " << destdir << (*libit) << "\n"
+ << "\t" << "-$(MOVE) " << (*libit) << " " << destdir << "\n";
+ }
+ }
+ t << endl << endl;
+ }
+
+ writeMakeQmake(t);
+ if(project->isEmpty("QMAKE_FAILED_REQUIREMENTS") && !project->isActiveConfig("no_autoqmake")) {
+ QString meta_files;
+ if(project->isActiveConfig("create_libtool") && project->first("TEMPLATE") == "lib" &&
+ !project->isActiveConfig("compile_libtool")) { //libtool
+ if(!meta_files.isEmpty())
+ meta_files += " ";
+ meta_files += libtoolFileName();
+ }
+ if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib") { //pkg-config
+ if(!meta_files.isEmpty())
+ meta_files += " ";
+ meta_files += pkgConfigFileName();
+ }
+ if(!meta_files.isEmpty())
+ t << escapeDependencyPath(meta_files) << ": " << "\n\t"
+ << "@$(QMAKE) -prl " << buildArgs() << " " << project->projectFile() << endl;
+ }
+
+ if(!project->first("QMAKE_PKGINFO").isEmpty()) {
+ QString pkginfo = escapeFilePath(project->first("QMAKE_PKGINFO"));
+ QString destdir = escapeFilePath(project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/Contents");
+ t << pkginfo << ": " << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "@$(DEL_FILE) " << pkginfo << "\n\t"
+ << "@echo \"APPL"
+ << (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4))
+ << "\" >" << pkginfo << endl;
+ }
+ if(!project->first("QMAKE_BUNDLE_RESOURCE_FILE").isEmpty()) {
+ QString resources = escapeFilePath(project->first("QMAKE_BUNDLE_RESOURCE_FILE"));
+ QString destdir = escapeFilePath(project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/Contents/Resources");
+ t << resources << ": " << "\n\t";
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "@touch " << resources << "\n\t" << endl;
+ }
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ //copy the plist
+ QString info_plist = escapeFilePath(fileFixify(project->first("QMAKE_INFO_PLIST"))),
+ info_plist_out = escapeFilePath(project->first("QMAKE_INFO_PLIST_OUT"));
+ QString destdir = info_plist_out.section(Option::dir_sep, 0, -2);
+ t << info_plist_out << ": " << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ QStringList commonSedArgs;
+ if (!project->values("VERSION").isEmpty())
+ commonSedArgs << "-e \"s,@SHORT_VERSION@," << project->first("VER_MAJ") << "." << project->first("VER_MIN") << ",g\" ";
+ commonSedArgs << "-e \"s,@TYPEINFO@,"<< (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ?
+ QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << ",g\" ";
+ if(project->first("TEMPLATE") == "app") {
+ QString icon = fileFixify(var("ICON"));
+ t << "@$(DEL_FILE) " << info_plist_out << "\n\t"
+ << "@sed ";
+ foreach (const QString &arg, commonSedArgs)
+ t << arg;
+ t << "-e \"s,@ICON@," << icon.section(Option::dir_sep, -1) << ",g\" "
+ << "-e \"s,@EXECUTABLE@," << var("QMAKE_ORIG_TARGET") << ",g\" "
+ << "-e \"s,@TYPEINFO@,"<< (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ?
+ QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << ",g\" "
+ << "" << info_plist << " >" << info_plist_out << endl;
+ //copy the icon
+ if(!project->isEmpty("ICON")) {
+ QString dir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/Contents/Resources/";
+ const QString icon_path = escapeFilePath(dir + icon.section(Option::dir_sep, -1));
+ t << icon_path << ": " << icon << "\n\t"
+ << mkdir_p_asstring(dir) << "\n\t"
+ << "@$(DEL_FILE) " << icon_path << "\n\t"
+ << "@$(COPY_FILE) " << escapeFilePath(icon) << " " << icon_path << endl;
+ }
+ } else {
+ t << "@$(DEL_FILE) " << info_plist_out << "\n\t"
+ << "@sed ";
+ foreach (const QString &arg, commonSedArgs)
+ t << arg;
+ t << "-e \"s,@LIBRARY@," << var("QMAKE_ORIG_TARGET") << ",g\" "
+ << "-e \"s,@TYPEINFO@,"
+ << (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ?
+ QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << ",g\" "
+ << "" << info_plist << " >" << info_plist_out << endl;
+ }
+ //copy other data
+ if(!project->isEmpty("QMAKE_BUNDLE_DATA")) {
+ QString bundle_dir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/";
+ const QStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA");
+ for(int i = 0; i < bundle_data.count(); i++) {
+ const QStringList &files = project->values(bundle_data[i] + ".files");
+ QString path = bundle_dir;
+ if(!project->isEmpty(bundle_data[i] + ".version")) {
+ QString version = project->first(bundle_data[i] + ".version") + "/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") + "/";
+ t << Option::fixPathToLocalOS(path + project->first(bundle_data[i] + ".path")) << ": " << "\n\t"
+ << mkdir_p_asstring(path) << "\n\t"
+ << "@$(SYMLINK) " << version << project->first(bundle_data[i] + ".path") << " " << path << endl;
+ path += version;
+ }
+ path += project->first(bundle_data[i] + ".path");
+ path = Option::fixPathToLocalOS(path);
+ for(int file = 0; file < files.count(); file++) {
+ QString src = fileFixify(files[file], FileFixifyAbsolute);
+ if (!QFile::exists(src))
+ src = files[file];
+ src = escapeFilePath(src);
+ const QString dst = escapeFilePath(path + Option::dir_sep + fileInfo(files[file]).fileName());
+ t << dst << ": " << src << "\n\t"
+ << mkdir_p_asstring(path) << "\n\t";
+ QFileInfo fi(fileInfo(files[file]));
+ if(fi.isDir())
+ t << "@$(DEL_FILE) -r " << dst << "\n\t"
+ << "@$(COPY_DIR) " << src << " " << dst << endl;
+ else
+ t << "@$(DEL_FILE) " << dst << "\n\t"
+ << "@$(COPY_FILE) " << src << " " << dst << endl;
+ }
+ }
+ }
+ }
+
+ QString ddir;
+ QString packageName(project->first("QMAKE_ORIG_TARGET"));
+ if(!project->isActiveConfig("no_dist_version"))
+ packageName += var("VERSION");
+ if (project->isEmpty("QMAKE_DISTDIR"))
+ ddir = packageName;
+ else
+ ddir = project->first("QMAKE_DISTDIR");
+
+ QString ddir_c = escapeFilePath(fileFixify((project->isEmpty("OBJECTS_DIR") ? QString(".tmp/") :
+ project->first("OBJECTS_DIR")) + ddir,
+ Option::output_dir, Option::output_dir));
+ t << "dist: " << "\n\t"
+ << mkdir_p_asstring(ddir_c) << "\n\t"
+ << "$(COPY_FILE) --parents $(SOURCES) $(DIST) " << ddir_c << Option::dir_sep << " && ";
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const QStringList &var = project->values((*it)+".input");
+ for(QStringList::ConstIterator var_it = var.begin(); var_it != var.end(); ++var_it) {
+ const QStringList &val = project->values((*var_it));
+ if(val.isEmpty())
+ continue;
+ t << "$(COPY_FILE) --parents " << val.join(" ") << " " << ddir_c << Option::dir_sep << " && ";
+ }
+ }
+ }
+ if(!project->isEmpty("TRANSLATIONS"))
+ t << "$(COPY_FILE) --parents " << var("TRANSLATIONS") << " " << ddir_c << Option::dir_sep << " && ";
+ t << "(cd `dirname " << ddir_c << "` && "
+ << "$(TAR) " << packageName << ".tar " << ddir << " && "
+ << "$(COMPRESS) " << packageName << ".tar) && "
+ << "$(MOVE) `dirname " << ddir_c << "`" << Option::dir_sep << packageName << ".tar.gz . && "
+ << "$(DEL_FILE) -r " << ddir_c
+ << endl << endl;
+
+ t << endl;
+
+ QString clean_targets = "compiler_clean " + var("CLEAN_DEPS");
+ if(do_incremental) {
+ t << "incrclean:" << "\n";
+ if(src_incremental)
+ t << "\t-$(DEL_FILE) $(INCREMENTAL_OBJECTS)" << "\n";
+ t << endl;
+ }
+
+ t << "clean:" << clean_targets << "\n\t";
+ if(!project->isEmpty("OBJECTS")) {
+ if(project->isActiveConfig("compile_libtool"))
+ t << "-$(LIBTOOL) --mode=clean $(DEL_FILE) $(OBJECTS)" << "\n\t";
+ else
+ t << "-$(DEL_FILE) $(OBJECTS)" << "\n\t";
+ }
+ if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")) {
+ QStringList precomp_files;
+ QString precomph_out_dir;
+
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ precomph_out_dir = project->first("PRECOMPILED_DIR");
+ precomph_out_dir += project->first("QMAKE_ORIG_TARGET");
+ if (!project->isActiveConfig("clang_pch_style"))
+ precomph_out_dir += project->first("QMAKE_PCH_OUTPUT_EXT");
+
+ if (project->isActiveConfig("icc_pch_style")) {
+ // icc style
+ QString pchBaseName = project->first("QMAKE_ORIG_TARGET");
+ QString pchOutput;
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ pchOutput = project->first("PRECOMPILED_DIR");
+ pchOutput += pchBaseName + project->first("QMAKE_PCH_OUTPUT_EXT");
+ QString sourceFile = pchOutput + Option::cpp_ext.first();
+ QString objectFile = createObjectList(QStringList(sourceFile)).first();
+
+ precomp_files << precomph_out_dir << sourceFile << objectFile;
+ } else {
+ // gcc style (including clang_pch_style)
+ precomph_out_dir += Option::dir_sep;
+
+ QString header_prefix = project->first("QMAKE_PRECOMP_PREFIX");
+ QString header_suffix = project->isActiveConfig("clang_pch_style")
+ ? project->first("QMAKE_PCH_OUTPUT_EXT") : "";
+
+ if(!project->isEmpty("QMAKE_CFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "c" + header_suffix;
+ if(!project->isEmpty("QMAKE_CXXFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "c++" + header_suffix;
+ if(project->isActiveConfig("objective_c")) {
+ if(!project->isEmpty("QMAKE_OBJCFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "objective-c" + header_suffix;
+ if(!project->isEmpty("QMAKE_OBJCXXFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "objective-c++" + header_suffix;
+ }
+ }
+ t << "-$(DEL_FILE) " << precomp_files.join(" ") << "\n\t";
+ }
+ if(!project->isEmpty("IMAGES"))
+ t << varGlue("QMAKE_IMAGE_COLLECTION", "\t-$(DEL_FILE) ", " ", "") << "\n\t";
+ if(src_incremental)
+ t << "-$(DEL_FILE) $(INCREMENTAL_OBJECTS)" << "\n\t";
+ t << varGlue("QMAKE_CLEAN","-$(DEL_FILE) "," ","\n\t")
+ << "-$(DEL_FILE) *~ core *.core" << "\n"
+ << varGlue("CLEAN_FILES","\t-$(DEL_FILE) "," ","") << endl << endl;
+ t << "####### Sub-libraries" << endl << endl;
+ if (!project->values("SUBLIBS").isEmpty()) {
+ QString libdir = "tmp/";
+ if(!project->isEmpty("SUBLIBS_DIR"))
+ libdir = project->first("SUBLIBS_DIR");
+ QStringList &l = project->values("SUBLIBS");
+ for(it = l.begin(); it != l.end(); ++it)
+ t << libdir << project->first("QMAKE_PREFIX_STATICLIB") << (*it) << "."
+ << project->first("QMAKE_EXTENSION_STATICLIB") << ":\n\t"
+ << var(QString("MAKELIB") + (*it)) << endl << endl;
+ }
+
+ QString destdir = project->first("DESTDIR");
+ if(!destdir.isEmpty() && destdir.right(1) != Option::dir_sep)
+ destdir += Option::dir_sep;
+ t << "distclean: " << "clean\n";
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundlePath = escapeFilePath(destdir + project->first("QMAKE_BUNDLE"));
+ t << "\t-$(DEL_FILE) -r " << bundlePath << endl;
+ } else if(project->isActiveConfig("compile_libtool")) {
+ t << "\t-$(LIBTOOL) --mode=clean $(DEL_FILE) " << "$(TARGET)" << endl;
+ } else if(!project->isActiveConfig("staticlib") && project->values("QMAKE_APP_FLAG").isEmpty() &&
+ !project->isActiveConfig("plugin")) {
+ t << "\t-$(DEL_FILE) " << destdir << "$(TARGET)" << " " << endl;
+ if (project->values("QMAKE_SYMBIAN_SHLIB").isEmpty())
+ t << "\t-$(DEL_FILE) " << destdir << "$(TARGET0) " << destdir << "$(TARGET1) "
+ << destdir << "$(TARGET2) $(TARGETA)" << endl;
+ } else {
+ t << "\t-$(DEL_FILE) " << "$(TARGET)" << " " << endl;
+ }
+ t << varGlue("QMAKE_DISTCLEAN","\t-$(DEL_FILE) "," ","\n");
+ {
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(!ofile.isEmpty())
+ t << "\t-$(DEL_FILE) " << ofile << endl;
+ }
+ t << endl << endl;
+
+ if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")) {
+ QString pchInput = project->first("PRECOMPILED_HEADER");
+ t << "###### Prefix headers" << endl;
+ QString comps[] = { "C", "CXX", "OBJC", "OBJCXX", QString() };
+ for(int i = 0; !comps[i].isNull(); i++) {
+ QString pchFlags = var("QMAKE_" + comps[i] + "FLAGS_PRECOMPILE");
+ if(pchFlags.isEmpty())
+ continue;
+
+ QString cflags;
+ if(comps[i] == "OBJC" || comps[i] == "OBJCXX")
+ cflags += " $(CFLAGS)";
+ else
+ cflags += " $(" + comps[i] + "FLAGS)";
+
+ QString pchBaseName = project->first("QMAKE_ORIG_TARGET");
+ QString pchOutput;
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ pchOutput = project->first("PRECOMPILED_DIR");
+ pchOutput += pchBaseName;
+ if (!project->isActiveConfig("clang_pch_style"))
+ pchOutput += project->first("QMAKE_PCH_OUTPUT_EXT");
+
+ if (project->isActiveConfig("icc_pch_style")) {
+ // icc style
+ QString sourceFile = pchOutput + Option::cpp_ext.first();
+ QString objectFile = createObjectList(QStringList(sourceFile)).first();
+ t << pchOutput << ": " << pchInput << " " << findDependencies(pchInput).join(" \\\n\t\t")
+ << "\n\techo \"// Automatically generated, do not modify\" > " << sourceFile
+ << "\n\trm -f " << pchOutput;
+
+ pchFlags = pchFlags.replace("${QMAKE_PCH_TEMP_SOURCE}", sourceFile)
+ .replace("${QMAKE_PCH_TEMP_OBJECT}", objectFile);
+ } else {
+ // gcc style (including clang_pch_style)
+ QString header_prefix = project->first("QMAKE_PRECOMP_PREFIX");
+ QString header_suffix = project->isActiveConfig("clang_pch_style")
+ ? project->first("QMAKE_PCH_OUTPUT_EXT") : "";
+ pchOutput += Option::dir_sep;
+ QString pchOutputDir = pchOutput, 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())
+ continue;
+ pchOutput += header_prefix + pchOutputFile + header_suffix;
+
+ t << pchOutput << ": " << pchInput << " " << findDependencies(pchInput).join(" \\\n\t\t")
+ << "\n\t" << mkdir_p_asstring(pchOutputDir);
+ }
+ pchFlags = pchFlags.replace("${QMAKE_PCH_INPUT}", pchInput)
+ .replace("${QMAKE_PCH_OUTPUT_BASE}", pchBaseName)
+ .replace("${QMAKE_PCH_OUTPUT}", pchOutput);
+
+ QString compiler;
+ if(comps[i] == "C" || comps[i] == "OBJC" || comps[i] == "OBJCXX")
+ compiler = "$(CC)";
+ else
+ compiler = "$(CXX)";
+
+ // compile command
+ t << "\n\t" << compiler << cflags << " $(INCPATH) " << pchFlags << endl << endl;
+ }
+ }
+
+ writeExtraTargets(t);
+ writeExtraCompilerTargets(t);
+}
+
+void UnixMakefileGenerator::init2()
+{
+ //version handling
+ if(project->isEmpty("VERSION"))
+ project->values("VERSION").append("1.0." +
+ (project->isEmpty("VER_PAT") ? QString("0") :
+ project->first("VER_PAT")));
+ QStringList l = project->first("VERSION").split('.');
+ l << "0" << "0"; //make sure there are three
+ project->values("VER_MAJ").append(l[0]);
+ project->values("VER_MIN").append(l[1]);
+ project->values("VER_PAT").append(l[2]);
+ if(project->isEmpty("QMAKE_FRAMEWORK_VERSION"))
+ project->values("QMAKE_FRAMEWORK_VERSION").append(project->values("VER_MAJ").first());
+
+ if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ project->values("TARGET").first().prepend(project->first("QMAKE_BUNDLE") + bundle_loc);
+ }
+ if(!project->isEmpty("TARGET"))
+ project->values("TARGET").first().prepend(project->first("DESTDIR"));
+ if (!project->values("QMAKE_CYGWIN_EXE").isEmpty())
+ project->values("TARGET_EXT").append(".exe");
+ } else if (project->isActiveConfig("staticlib")) {
+ project->values("TARGET").first().prepend(project->first("QMAKE_PREFIX_STATICLIB"));
+ project->values("TARGET").first() += "." + project->first("QMAKE_EXTENSION_STATICLIB");
+ if(project->values("QMAKE_AR_CMD").isEmpty())
+ project->values("QMAKE_AR_CMD").append("$(AR) $(TARGET) $(OBJECTS)");
+ } else {
+ project->values("TARGETA").append(project->first("DESTDIR") + project->first("QMAKE_PREFIX_STATICLIB")
+ + project->first("TARGET") + "." + project->first("QMAKE_EXTENSION_STATICLIB"));
+ if(project->isActiveConfig("compile_libtool"))
+ project->values("TARGET_la") = QStringList(project->first("DESTDIR") + "lib" + project->first("TARGET") + Option::libtool_ext);
+
+ if (!project->values("QMAKE_AR_CMD").isEmpty())
+ project->values("QMAKE_AR_CMD").first().replace("(TARGET)","(TARGETA)");
+ else
+ project->values("QMAKE_AR_CMD").append("$(AR) $(TARGETA) $(OBJECTS)");
+ if(project->isActiveConfig("compile_libtool")) {
+ project->values("TARGET") = project->values("TARGET_la");
+ } else if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ project->values("TARGET_").append(project->first("QMAKE_BUNDLE") +
+ bundle_loc + unescapeFilePath(project->first("TARGET")));
+ project->values("TARGET_x.y").append(project->first("QMAKE_BUNDLE") +
+ "/Versions/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") +
+ bundle_loc + unescapeFilePath(project->first("TARGET")));
+ } else if(project->isActiveConfig("plugin")) {
+ QString prefix;
+ if(!project->isActiveConfig("no_plugin_name_prefix"))
+ prefix = "lib";
+ project->values("TARGET_x.y.z").append(prefix +
+ project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_PLUGIN"));
+ if(project->isActiveConfig("lib_version_first"))
+ project->values("TARGET_x").append(prefix + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("QMAKE_EXTENSION_PLUGIN"));
+ else
+ project->values("TARGET_x").append(prefix + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_PLUGIN") +
+ "." + project->first("VER_MAJ"));
+ project->values("TARGET") = project->values("TARGET_x.y.z");
+ } else if (!project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ project->values("TARGET_").append("lib" + project->first("TARGET") + ".sl");
+ if(project->isActiveConfig("lib_version_first"))
+ project->values("TARGET_x").append("lib" + project->first("VER_MAJ") + "." +
+ project->first("TARGET"));
+ else
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ"));
+ project->values("TARGET") = project->values("TARGET_x");
+ } else if (!project->isEmpty("QMAKE_AIX_SHLIB")) {
+ project->values("TARGET_").append(project->first("QMAKE_PREFIX_STATICLIB") + project->first("TARGET")
+ + "." + project->first("QMAKE_EXTENSION_STATICLIB"));
+ if(project->isActiveConfig("lib_version_first")) {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") +
+ "." + project->first("VER_MIN") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ } else {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") +
+ "." + project->first("VER_MAJ"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") +
+ "." + project->first("VER_MAJ") +
+ "." + project->first("VER_MIN"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT"));
+ }
+ project->values("TARGET") = project->values("TARGET_x.y.z");
+ } else if (!project->isEmpty("QMAKE_SYMBIAN_SHLIB")) {
+ project->values("TARGET_").append(project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET") = project->values("TARGET_");
+ } else {
+ project->values("TARGET_").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ if(project->isActiveConfig("lib_version_first")) {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") +
+ "." + project->first("VER_MIN") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT") + "." +
+ project->values("QMAKE_EXTENSION_SHLIB").first());
+ } else {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") +
+ "." + project->first("VER_MAJ"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB")
+ + "." + project->first("VER_MAJ") +
+ "." + project->first("VER_MIN"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") +
+ "." +
+ project->values(
+ "QMAKE_EXTENSION_SHLIB").first() + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT"));
+ }
+ project->values("TARGET") = project->values("TARGET_x.y.z");
+ }
+ if(project->isEmpty("QMAKE_LN_SHLIB"))
+ project->values("QMAKE_LN_SHLIB").append("ln -s");
+ if (!project->values("QMAKE_LFLAGS_SONAME").isEmpty()) {
+ QString soname;
+ if(project->isActiveConfig("plugin")) {
+ if(!project->values("TARGET").isEmpty())
+ soname += project->first("TARGET");
+ } else if(!project->isEmpty("QMAKE_BUNDLE")) {
+ soname += project->first("TARGET_x.y");
+ } else if(!project->values("TARGET_x").isEmpty()) {
+ soname += project->first("TARGET_x");
+ }
+ if(!soname.isEmpty()) {
+ if(project->isActiveConfig("absolute_library_soname") &&
+ project->values("INSTALLS").indexOf("target") != -1 &&
+ !project->isEmpty("target.path")) {
+ QString instpath = Option::fixPathToTargetOS(project->first("target.path"));
+ if(!instpath.endsWith(Option::dir_sep))
+ instpath += Option::dir_sep;
+ soname.prepend(instpath);
+ }
+ project->values("QMAKE_LFLAGS_SONAME").first() += escapeFilePath(soname);
+ }
+ }
+ if (project->values("QMAKE_LINK_SHLIB_CMD").isEmpty())
+ project->values("QMAKE_LINK_SHLIB_CMD").append(
+ "$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP)");
+ }
+ if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_APP");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_APP");
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_APP");
+ } else if (project->isActiveConfig("dll")) {
+ if(!project->isActiveConfig("plugin") || !project->isActiveConfig("plugin_no_share_shlib_cflags")) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_SHLIB");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_SHLIB");
+ }
+ if (project->isActiveConfig("plugin")) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_PLUGIN");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_PLUGIN");
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PLUGIN");
+ if(project->isActiveConfig("plugin_with_soname") && !project->isActiveConfig("compile_libtool"))
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SONAME");
+ } else {
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SHLIB");
+ if(!project->isEmpty("QMAKE_LFLAGS_COMPAT_VERSION")) {
+ if(project->isEmpty("COMPAT_VERSION"))
+ project->values("QMAKE_LFLAGS") += QString(project->first("QMAKE_LFLAGS_COMPAT_VERSION") +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN"));
+ else
+ project->values("QMAKE_LFLAGS") += QString(project->first("QMAKE_LFLAGS_COMPAT_VERSION") +
+ project->first("COMPATIBILITY_VERSION"));
+ }
+ if(!project->isEmpty("QMAKE_LFLAGS_VERSION")) {
+ project->values("QMAKE_LFLAGS") += QString(project->first("QMAKE_LFLAGS_VERSION") +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT"));
+ }
+ if(!project->isActiveConfig("compile_libtool"))
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SONAME");
+ }
+ }
+
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString plist = fileFixify(project->first("QMAKE_INFO_PLIST"));
+ if(plist.isEmpty())
+ plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE");
+ if(exists(Option::fixPathToLocalOS(plist))) {
+ if(project->isEmpty("QMAKE_INFO_PLIST"))
+ project->values("QMAKE_INFO_PLIST").append(plist);
+ project->values("QMAKE_INFO_PLIST_OUT").append(project->first("DESTDIR") +
+ project->first("QMAKE_BUNDLE") +
+ "/Contents/Info.plist");
+ project->values("ALL_DEPS") += project->first("QMAKE_INFO_PLIST_OUT");
+ if(!project->isEmpty("ICON") && project->first("TEMPLATE") == "app")
+ project->values("ALL_DEPS") += project->first("DESTDIR") +
+ project->first("QMAKE_BUNDLE") +
+ "/Contents/Resources/" + project->first("ICON").section('/', -1);
+ if(!project->isEmpty("QMAKE_BUNDLE_DATA")) {
+ QString bundle_dir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/";
+ QStringList &alldeps = project->values("ALL_DEPS");
+ const QStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA");
+ for(int i = 0; i < bundle_data.count(); i++) {
+ const QStringList &files = project->values(bundle_data[i] + ".files");
+ QString path = bundle_dir;
+ if(!project->isEmpty(bundle_data[i] + ".version")) {
+ alldeps += Option::fixPathToLocalOS(path + Option::dir_sep +
+ project->first(bundle_data[i] + ".path"));
+ path += project->first(bundle_data[i] + ".version") + "/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") + "/";
+ }
+ path += project->first(bundle_data[i] + ".path");
+ path = Option::fixPathToLocalOS(path);
+ for(int file = 0; file < files.count(); file++)
+ alldeps += path + Option::dir_sep + fileInfo(files[file]).fileName();
+ }
+ }
+ }
+ }
+}
+
+QString
+UnixMakefileGenerator::libtoolFileName(bool fixify)
+{
+ QString ret = var("TARGET");
+ int slsh = ret.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ ret = ret.right(ret.length() - slsh - 1);
+ int dot = ret.indexOf('.');
+ if(dot != -1)
+ ret = ret.left(dot);
+ ret += Option::libtool_ext;
+ if(!project->isEmpty("QMAKE_LIBTOOL_DESTDIR"))
+ ret.prepend(project->first("QMAKE_LIBTOOL_DESTDIR") + Option::dir_sep);
+ 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;
+}
+
+void
+UnixMakefileGenerator::writeLibtoolFile()
+{
+ QString fname = libtoolFileName(), 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);
+ t << "# " << lname << " - a libtool library file\n";
+ t << "# Generated by qmake/libtool (" << qmake_version() << ") (Qt "
+ << QT_VERSION_STR << ") on: " << QDateTime::currentDateTime().toString();
+ t << "\n";
+
+ t << "# The name that we can dlopen(3).\n"
+ << "dlname='" << var(project->isActiveConfig("plugin") ? "TARGET" : "TARGET_x")
+ << "'\n\n";
+
+ t << "# Names of this library.\n";
+ t << "library_names='";
+ if(project->isActiveConfig("plugin")) {
+ t << var("TARGET");
+ } else {
+ if (project->isEmpty("QMAKE_HPUX_SHLIB"))
+ t << var("TARGET_x.y.z") << " ";
+ t << var("TARGET_x") << " " << var("TARGET_");
+ }
+ t << "'\n\n";
+
+ t << "# The name of the static archive.\n"
+ << "old_library='" << lname.left(lname.length()-Option::libtool_ext.length()) << ".a'\n\n";
+
+ t << "# Libraries that this one depends upon.\n";
+ QStringList libs;
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ libs = project->values("QMAKE_INTERNAL_PRL_LIBS");
+ else
+ libs << "QMAKE_LIBS"; //obvious one
+ t << "dependency_libs='";
+ for(QStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it)
+ t << project->values((*it)).join(" ") << " ";
+ t << "'\n\n";
+
+ t << "# Version information for " << lname << "\n";
+ int maj = project->first("VER_MAJ").toInt();
+ int min = project->first("VER_MIN").toInt();
+ int pat = project->first("VER_PAT").toInt();
+ t << "current=" << (10*maj + min) << "\n" // best I can think of
+ << "age=0\n"
+ << "revision=" << pat << "\n\n";
+
+ t << "# Is this an already installed library.\n"
+ "installed=yes\n\n"; // ###
+
+ t << "# Files to dlopen/dlpreopen.\n"
+ "dlopen=''\n"
+ "dlpreopen=''\n\n";
+
+ QString install_dir = project->first("QMAKE_LIBTOOL_LIBDIR");
+ if(install_dir.isEmpty())
+ install_dir = project->first("target.path");
+ if(install_dir.isEmpty())
+ install_dir = project->first("DESTDIR");
+ t << "# Directory that this library needs to be installed in:\n"
+ "libdir='" << Option::fixPathToTargetOS(install_dir, false) << "'\n";
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/borland_bmake.cpp b/qmake/generators/win32/borland_bmake.cpp
new file mode 100644
index 0000000000..585a0f4982
--- /dev/null
+++ b/qmake/generators/win32/borland_bmake.cpp
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** 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 "borland_bmake.h"
+#include "option.h"
+#include <qdir.h>
+#include <qregexp.h>
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+BorlandMakefileGenerator::BorlandMakefileGenerator() : Win32MakefileGenerator(), init_flag(false)
+{
+
+}
+
+bool
+BorlandMakefileGenerator::writeMakefile(QTextStream &t)
+{
+ writeHeader(t);
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
+ t << *it << " ";
+ t << "all first clean:" << "\n\t"
+ << "@echo \"Some of the required modules ("
+ << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
+ << "@echo \"Skipped.\"" << endl << endl;
+ return true;
+ }
+
+ if(project->first("TEMPLATE") == "app" ||
+ project->first("TEMPLATE") == "lib") {
+ writeBorlandParts(t);
+ return MakefileGenerator::writeMakefile(t);
+ }
+ else if(project->first("TEMPLATE") == "subdirs") {
+ writeSubDirs(t);
+ return true;
+ }
+ return false;
+}
+
+void
+BorlandMakefileGenerator::writeBorlandParts(QTextStream &t)
+{
+ t << "!if !$d(BCB)" << endl;
+ t << "BCB = $(MAKEDIR)\\.." << endl;
+ t << "!endif" << endl << endl;
+
+ writeStandardParts(t);
+}
+
+void
+BorlandMakefileGenerator::init()
+{
+ if(init_flag)
+ return;
+ init_flag = true;
+
+ /* 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("QMAKE_COPY_FILE"))
+ project->values("QMAKE_COPY_FILE").append("$(COPY)");
+ if(project->isEmpty("QMAKE_COPY_DIR"))
+ project->values("QMAKE_COPY_DIR").append("xcopy /s /q /y /i");
+ if(project->isEmpty("QMAKE_INSTALL_FILE"))
+ project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
+ project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_DIR"))
+ project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
+ if(project->values("MAKEFILE").isEmpty())
+ project->values("MAKEFILE").append("Makefile");
+ return;
+ }
+
+ processVars();
+
+ project->values("QMAKE_LIBS") += project->values("LIBS");
+
+ MakefileGenerator::init();
+
+ if (project->isActiveConfig("dll") || !project->values("QMAKE_APP_FLAG").isEmpty()) {
+ // bcc does not generate a .tds file for static libs
+ QString tdsPostfix;
+ if (!project->values("VERSION").isEmpty())
+ tdsPostfix = project->first("TARGET_VERSION_EXT");
+ tdsPostfix += ".tds";
+ project->values("QMAKE_CLEAN").append(project->first("DESTDIR") + project->first("TARGET") + tdsPostfix);
+ }
+}
+
+void BorlandMakefileGenerator::writeBuildRulesPart(QTextStream &t)
+{
+ t << "first: all" << endl;
+ t << "all: " << fileFixify(Option::output.fileName()) << " " << varGlue("ALL_DEPS"," "," "," ") << " $(DESTDIR_TARGET)" << endl << endl;
+ t << "$(DESTDIR_TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) " << var("POST_TARGETDEPS");
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << "\n\t" <<var("QMAKE_PRE_LINK");
+ if(project->isActiveConfig("staticlib")) {
+ t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET)"
+ << "\n\t" << "$(LIB) $(DESTDIR_TARGET) @&&|" << " \n+"
+ << project->values("OBJECTS").join(" \\\n+") << " \\\n+"
+ << project->values("OBJMOC").join(" \\\n+");
+ } else {
+ t << "\n\t" << "$(LINK) @&&|" << "\n\t"
+ << "$(LFLAGS) $(OBJECTS) $(OBJMOC),$(DESTDIR_TARGET),,$(LIBS),$(DEF_FILE),$(RES_FILE)";
+ }
+ t << endl << "|";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" <<var("QMAKE_POST_LINK");
+ t << endl;
+}
+
+void BorlandMakefileGenerator::writeCleanParts(QTextStream &t)
+{
+ t << "clean: "
+ << varGlue("OBJECTS","\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","")
+ << varGlue("QMAKE_CLEAN","\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","\n")
+ << varGlue("CLEAN_FILES","\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","\n");
+
+ if(!project->isEmpty("IMAGES"))
+ t << varGlue("QMAKE_IMAGE_COLLECTION", "\n\t-$(DEL_FILE) ", "\n\t-$(DEL_FILE) ", "");
+ t << endl;
+
+ t << "distclean: clean"
+ << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET)"
+ << endl << endl;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/borland_bmake.h b/qmake/generators/win32/borland_bmake.h
new file mode 100644
index 0000000000..7a2734f5e3
--- /dev/null
+++ b/qmake/generators/win32/borland_bmake.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 BORLAND_BMAKE_H
+#define BORLAND_BMAKE_H
+
+#include "winmakefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class BorlandMakefileGenerator : public Win32MakefileGenerator
+{
+ bool init_flag;
+ void writeBorlandParts(QTextStream &);
+ void writeBuildRulesPart(QTextStream &t);
+ void writeCleanParts(QTextStream &t);
+ bool writeMakefile(QTextStream &);
+ void init();
+
+public:
+ BorlandMakefileGenerator();
+ ~BorlandMakefileGenerator();
+};
+
+inline BorlandMakefileGenerator::~BorlandMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // BORLAND_BMAKE_H
diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp
new file mode 100644
index 0000000000..462920e06c
--- /dev/null
+++ b/qmake/generators/win32/mingw_make.cpp
@@ -0,0 +1,516 @@
+/****************************************************************************
+**
+** 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 "mingw_make.h"
+#include "option.h"
+#include "meta.h"
+#include <qregexp.h>
+#include <qdir.h>
+#include <stdlib.h>
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+MingwMakefileGenerator::MingwMakefileGenerator() : Win32MakefileGenerator(), init_flag(false)
+{
+ if (Option::shellPath.isEmpty())
+ quote = "\"";
+ else
+ quote = "'";
+}
+
+bool MingwMakefileGenerator::isWindowsShell() const
+{
+#ifdef Q_OS_WIN
+ return Option::shellPath.isEmpty();
+#else
+ return Win32MakefileGenerator::isWindowsShell();
+#endif
+}
+
+QString MingwMakefileGenerator::escapeDependencyPath(const QString &path) const
+{
+ QString ret = path;
+ ret.remove('\"');
+ ret.replace('\\', "/");
+ ret.replace(' ', "\\ ");
+ return ret;
+}
+
+QString MingwMakefileGenerator::getLibTarget()
+{
+ return QString("lib" + project->first("TARGET") + project->first("TARGET_VERSION_EXT") + ".a");
+}
+
+bool MingwMakefileGenerator::findLibraries()
+{
+ return findLibraries("QMAKE_LIBS") && findLibraries("QMAKE_LIBS_PRIVATE");
+}
+
+bool MingwMakefileGenerator::findLibraries(const QString &where)
+{
+ QStringList &l = project->values(where);
+
+ QList<QMakeLocalFileName> dirs;
+ {
+ QStringList &libpaths = project->values("QMAKE_LIBDIR");
+ for(QStringList::Iterator libpathit = libpaths.begin();
+ libpathit != libpaths.end(); ++libpathit)
+ dirs.append(QMakeLocalFileName((*libpathit)));
+ }
+
+ QStringList::Iterator it = l.begin();
+ while (it != l.end()) {
+ if ((*it).startsWith("-l")) {
+ QString steam = (*it).mid(2), out;
+ QString suffix;
+ if (!project->isEmpty("QMAKE_" + steam.toUpper() + "_SUFFIX"))
+ suffix = project->first("QMAKE_" + steam.toUpper() + "_SUFFIX");
+ for (QList<QMakeLocalFileName>::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
+ QString extension;
+ int ver = findHighestVersion((*dir_it).local(), steam, "dll.a|a");
+ if (ver != -1)
+ extension += QString::number(ver);
+ extension += suffix;
+ if(QMakeMetaInfo::libExists((*dir_it).local() + Option::dir_sep + steam) ||
+ exists((*dir_it).local() + Option::dir_sep + steam + extension + ".a") ||
+ exists((*dir_it).local() + Option::dir_sep + steam + extension + ".dll.a")) {
+ out = (*it) + extension;
+ break;
+ }
+ }
+ if (!out.isEmpty()) // We assume if it never finds it that its correct
+ (*it) = out;
+ } else if((*it).startsWith("-L")) {
+ dirs.append(QMakeLocalFileName((*it).mid(2)));
+ }
+
+ ++it;
+ }
+ return true;
+}
+
+bool MingwMakefileGenerator::writeMakefile(QTextStream &t)
+{
+ writeHeader(t);
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ t << "all clean:" << "\n\t"
+ << "@echo \"Some of the required modules ("
+ << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
+ << "@echo \"Skipped.\"" << endl << endl;
+ writeMakeQmake(t);
+ return true;
+ }
+
+ if(project->first("TEMPLATE") == "app" ||
+ project->first("TEMPLATE") == "lib") {
+ if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib")
+ writePkgConfigFile();
+
+ if(Option::mkfile::do_stub_makefile) {
+ 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 << " ";
+ 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;
+ }
+ writeMingwParts(t);
+ return MakefileGenerator::writeMakefile(t);
+ }
+ else if(project->first("TEMPLATE") == "subdirs") {
+ writeSubDirs(t);
+ return true;
+ }
+ return false;
+ }
+
+void createLdObjectScriptFile(const QString &fileName, const QStringList &objList)
+{
+ QString filePath = Option::output_dir + QDir::separator() + fileName;
+ QFile file(filePath);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ QTextStream t(&file);
+ t << "INPUT(" << endl;
+ for (QStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) {
+ if (QDir::isRelativePath(*it))
+ t << "./" << *it << endl;
+ else
+ t << *it << endl;
+ }
+ t << ");" << endl;
+ t.flush();
+ file.close();
+ }
+}
+
+void createArObjectScriptFile(const QString &fileName, const QString &target, const QStringList &objList)
+{
+ QString filePath = Option::output_dir + QDir::separator() + fileName;
+ QFile file(filePath);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ QTextStream t(&file);
+ t << "CREATE " << target << endl;
+ for (QStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) {
+ t << "ADDMOD " << *it << endl;
+ }
+ t << "SAVE" << endl;
+ t.flush();
+ file.close();
+ }
+}
+
+void createRvctObjectScriptFile(const QString &fileName, const QStringList &objList)
+{
+ QString filePath = Option::output_dir + QDir::separator() + fileName;
+ QFile file(filePath);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ QTextStream t(&file);
+ for (QStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) {
+ if (QDir::isRelativePath(*it))
+ t << "./" << *it << endl;
+ else
+ t << *it << endl;
+ }
+ t.flush();
+ file.close();
+ }
+}
+
+void MingwMakefileGenerator::writeMingwParts(QTextStream &t)
+{
+ if (!project->isEmpty("QMAKE_SYMBIAN_SHLIB")) {
+ t << "vpath %.dso " << project->values("QMAKE_LIBDIR").join(";") << endl;
+ t << "vpath %.lib " << project->values("QMAKE_LIBDIR").join(";") << endl;
+ t << "\n\n";
+ }
+
+ writeStandardParts(t);
+
+ if (!preCompHeaderOut.isEmpty()) {
+ QString header = project->first("PRECOMPILED_HEADER");
+ QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
+ t << escapeDependencyPath(cHeader) << ": " << escapeDependencyPath(header) << " "
+ << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
+ << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
+ << "\n\t" << "$(CC) -x c-header -c $(CFLAGS) $(INCPATH) -o " << cHeader << " " << header
+ << endl << endl;
+ QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
+ t << escapeDependencyPath(cppHeader) << ": " << escapeDependencyPath(header) << " "
+ << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
+ << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
+ << "\n\t" << "$(CXX) -x c++-header -c $(CXXFLAGS) $(INCPATH) -o " << cppHeader << " " << header
+ << endl << endl;
+ }
+}
+
+void MingwMakefileGenerator::init()
+{
+ if(init_flag)
+ return;
+ init_flag = true;
+
+ /* 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("QMAKE_COPY_FILE"))
+ project->values("QMAKE_COPY_FILE").append("$(COPY)");
+ if(project->isEmpty("QMAKE_COPY_DIR"))
+ project->values("QMAKE_COPY_DIR").append("xcopy /s /q /y /i");
+ if(project->isEmpty("QMAKE_INSTALL_FILE"))
+ project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
+ project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_DIR"))
+ project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
+ if(project->values("MAKEFILE").isEmpty())
+ project->values("MAKEFILE").append("Makefile");
+ return;
+ }
+
+ project->values("TARGET_PRL").append(project->first("TARGET"));
+
+ processVars();
+
+ if (!project->values("RES_FILE").isEmpty()) {
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("RES_FILE"));
+ }
+
+ // LIBS defined in Profile comes first for gcc
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
+ project->values("QMAKE_LIBS_PRIVATE") += escapeFilePaths(project->values("LIBS_PRIVATE"));
+
+ QString targetfilename = project->values("TARGET").first();
+ QStringList &configs = project->values("CONFIG");
+
+ if(project->isActiveConfig("qt_dll"))
+ if(configs.indexOf("qt") == -1)
+ configs.append("qt");
+
+ if(project->isActiveConfig("dll") && project->values("QMAKE_SYMBIAN_SHLIB").isEmpty()) {
+ QString destDir = "";
+ if(!project->first("DESTDIR").isEmpty())
+ destDir = Option::fixPathToTargetOS(project->first("DESTDIR") + Option::dir_sep, false, false);
+ project->values("MINGW_IMPORT_LIB").prepend(destDir + "lib" + project->first("TARGET")
+ + project->first("TARGET_VERSION_EXT") + ".a");
+ project->values("QMAKE_LFLAGS").append(QString("-Wl,--out-implib,") + project->first("MINGW_IMPORT_LIB"));
+ }
+
+ if(!project->values("DEF_FILE").isEmpty() && project->values("QMAKE_SYMBIAN_SHLIB").isEmpty()) {
+ QString defFileName = fileFixify(project->values("DEF_FILE")).first();
+ project->values("QMAKE_LFLAGS").append(QString("-Wl,") + escapeFilePath(defFileName));
+ }
+
+ MakefileGenerator::init();
+
+ // precomp
+ if (!project->first("PRECOMPILED_HEADER").isEmpty()
+ && project->isActiveConfig("precompile_header")) {
+ QString preCompHeader = var("PRECOMPILED_DIR")
+ + QFileInfo(project->first("PRECOMPILED_HEADER")).fileName();
+ preCompHeaderOut = preCompHeader + ".gch";
+ project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c");
+ project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c++");
+
+ project->values("QMAKE_RUN_CC").clear();
+ project->values("QMAKE_RUN_CC").append("$(CC) -c -include " + preCompHeader +
+ " $(CFLAGS) $(INCPATH) -o $obj $src");
+ project->values("QMAKE_RUN_CC_IMP").clear();
+ project->values("QMAKE_RUN_CC_IMP").append("$(CC) -c -include " + preCompHeader +
+ " $(CFLAGS) $(INCPATH) -o $@ $<");
+ project->values("QMAKE_RUN_CXX").clear();
+ project->values("QMAKE_RUN_CXX").append("$(CXX) -c -include " + preCompHeader +
+ " $(CXXFLAGS) $(INCPATH) -o $obj $src");
+ project->values("QMAKE_RUN_CXX_IMP").clear();
+ project->values("QMAKE_RUN_CXX_IMP").append("$(CXX) -c -include " + preCompHeader +
+ " $(CXXFLAGS) $(INCPATH) -o $@ $<");
+ }
+
+ if(project->isActiveConfig("dll")) {
+ project->values("QMAKE_CLEAN").append(project->first("MINGW_IMPORT_LIB"));
+ }
+}
+
+void MingwMakefileGenerator::fixTargetExt()
+{
+ if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
+ project->values("QMAKE_LFLAGS").append("-static");
+ }
+ Win32MakefileGenerator::fixTargetExt();
+}
+
+void MingwMakefileGenerator::writeIncPart(QTextStream &t)
+{
+ t << "INCPATH = ";
+
+ QStringList &incs = project->values("INCLUDEPATH");
+ for(QStringList::Iterator incit = incs.begin(); incit != incs.end(); ++incit) {
+ QString inc = (*incit);
+ inc.replace(QRegExp("\\\\$"), "");
+ inc.replace(QRegExp("\""), "");
+ t << "-I" << quote << inc << quote << " ";
+ }
+ t << "-I" << quote << specdir() << quote
+ << endl;
+}
+
+void MingwMakefileGenerator::writeLibsPart(QTextStream &t)
+{
+ if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
+ t << "LIB = " << var("QMAKE_LIB") << endl;
+ } else {
+ t << "LINK = " << var("QMAKE_LINK") << endl;
+ t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl;
+ t << "LIBS = ";
+ if(!project->values("QMAKE_LIBDIR").isEmpty())
+ writeLibDirPart(t);
+ if (project->isActiveConfig("rvct_linker")) {
+ t << var("QMAKE_LIBS") << ' '
+ << var("QMAKE_LIBS_PRIVATE") << endl;
+ } else {
+ t << var("QMAKE_LIBS").replace(QRegExp("(\\slib|^lib)")," -l") << ' '
+ << var("QMAKE_LIBS_PRIVATE").replace(QRegExp("(\\slib|^lib)")," -l") << endl;
+ }
+ }
+}
+
+void MingwMakefileGenerator::writeLibDirPart(QTextStream &t)
+{
+ QStringList libDirs = project->values("QMAKE_LIBDIR");
+ QString libArg = QString::fromLatin1("-L");
+ if (project->isActiveConfig("rvct_linker"))
+ libArg = QString::fromLatin1("--userlibpath ");
+ for (int i = 0; i < libDirs.size(); ++i) {
+ libDirs[i].remove("\"");
+ if (libDirs[i].endsWith("\\"))
+ libDirs[i].chop(1);
+ }
+ t << valGlue(libDirs, libArg+quote, quote+" "+libArg+quote, quote) << " ";
+}
+
+void MingwMakefileGenerator::writeObjectsPart(QTextStream &t)
+{
+ if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) {
+ objectsLinkLine = "$(OBJECTS)";
+ } else if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
+ QString ar_script_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET");
+ if (!var("BUILD_NAME").isEmpty()) {
+ ar_script_file += "." + var("BUILD_NAME");
+ }
+ // QMAKE_LIB is used for win32, including mingw, whereas QMAKE_AR is used on Unix.
+ if (project->isActiveConfig("rvct_linker")) {
+ createRvctObjectScriptFile(ar_script_file, project->values("OBJECTS"));
+ QString ar_cmd = project->values("QMAKE_LIB").join(" ");
+ if (ar_cmd.isEmpty())
+ ar_cmd = "armar --create";
+ objectsLinkLine = ar_cmd + " " + var("DEST_TARGET") + " --via " + ar_script_file;
+ } else {
+ // Strip off any options since the ar commands will be read from file.
+ QString ar_cmd = var("QMAKE_LIB").section(" ", 0, 0);;
+ if (ar_cmd.isEmpty())
+ ar_cmd = "ar";
+ createArObjectScriptFile(ar_script_file, var("DEST_TARGET"), project->values("OBJECTS"));
+ objectsLinkLine = ar_cmd + " -M < " + ar_script_file;
+ }
+ } else {
+ QString ld_script_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET");
+ if (!var("BUILD_NAME").isEmpty()) {
+ ld_script_file += "." + var("BUILD_NAME");
+ }
+ if (project->isActiveConfig("rvct_linker")) {
+ createRvctObjectScriptFile(ld_script_file, project->values("OBJECTS"));
+ objectsLinkLine = QString::fromLatin1("--via ") + ld_script_file;
+ } else {
+ createLdObjectScriptFile(ld_script_file, project->values("OBJECTS"));
+ objectsLinkLine = ld_script_file;
+ }
+ }
+ Win32MakefileGenerator::writeObjectsPart(t);
+}
+
+void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t)
+{
+ t << "first: all" << endl;
+ t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName())) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS"))," "," "," ") << " $(DESTDIR_TARGET)" << endl << endl;
+ t << "$(DESTDIR_TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) " << var("POST_TARGETDEPS");
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << "\n\t" <<var("QMAKE_PRE_LINK");
+ if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
+ if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) {
+ t << "\n\t" << "$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ;
+ } else {
+ t << "\n\t" << objectsLinkLine << " " ;
+ }
+ } else {
+ t << "\n\t" << "$(LINK) $(LFLAGS) -o $(DESTDIR_TARGET) " << objectsLinkLine << " " << " $(LIBS)";
+ }
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" <<var("QMAKE_POST_LINK");
+ t << endl;
+}
+
+void MingwMakefileGenerator::writeRcFilePart(QTextStream &t)
+{
+ const QString rc_file = fileFixify(project->first("RC_FILE"));
+
+ QString incPathStr = fileInfo(rc_file).path();
+ if (incPathStr != "." && QDir::isRelativePath(incPathStr))
+ incPathStr.prepend("./");
+
+ if (!rc_file.isEmpty()) {
+ t << escapeDependencyPath(var("RES_FILE")) << ": " << rc_file << "\n\t"
+ << var("QMAKE_RC") << " -i " << rc_file << " -o " << var("RES_FILE")
+ << " --include-dir=" << incPathStr << " $(DEFINES)" << endl << endl;
+ }
+}
+
+void MingwMakefileGenerator::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) {
+ out.removeAll((*it));
+ out.append((*it));
+ }
+ } else {
+ Win32MakefileGenerator::processPrlVariable(var, l);
+ }
+}
+
+QStringList &MingwMakefileGenerator::findDependencies(const QString &file)
+{
+ QStringList &aList = MakefileGenerator::findDependencies(file);
+ // Note: The QMAKE_IMAGE_COLLECTION file have all images
+ // as dependency, so don't add precompiled header then
+ if (file == project->first("QMAKE_IMAGE_COLLECTION")
+ || preCompHeaderOut.isEmpty())
+ return aList;
+ for (QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
+ if (file.endsWith(*it)) {
+ QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
+ if (!aList.contains(cHeader))
+ aList += cHeader;
+ break;
+ }
+ }
+ for (QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
+ if (file.endsWith(*it)) {
+ QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
+ if (!aList.contains(cppHeader))
+ aList += cppHeader;
+ break;
+ }
+ }
+ return aList;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/mingw_make.h b/qmake/generators/win32/mingw_make.h
new file mode 100644
index 0000000000..5bc9c7b3b4
--- /dev/null
+++ b/qmake/generators/win32/mingw_make.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 MINGW_MAKE_H
+#define MINGW_MAKE_H
+
+#include "winmakefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class MingwMakefileGenerator : public Win32MakefileGenerator
+{
+public:
+ MingwMakefileGenerator();
+ ~MingwMakefileGenerator();
+protected:
+ QString escapeDependencyPath(const QString &path) const;
+ QString getLibTarget();
+ bool writeMakefile(QTextStream &);
+ void init();
+private:
+ bool isWindowsShell() const;
+ void writeMingwParts(QTextStream &);
+ void writeIncPart(QTextStream &t);
+ void writeLibsPart(QTextStream &t);
+ void writeLibDirPart(QTextStream &t);
+ void writeObjectsPart(QTextStream &t);
+ void writeBuildRulesPart(QTextStream &t);
+ void writeRcFilePart(QTextStream &t);
+ void processPrlVariable(const QString &var, const QStringList &l);
+
+ QStringList &findDependencies(const QString &file);
+
+ QString preCompHeaderOut;
+
+ virtual bool findLibraries();
+ bool findLibraries(const QString &where);
+ void fixTargetExt();
+
+ bool init_flag;
+ QString objectsLinkLine;
+ QString quote;
+};
+
+inline MingwMakefileGenerator::~MingwMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // MINGW_MAKE_H
diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp
new file mode 100644
index 0000000000..d4d2400146
--- /dev/null
+++ b/qmake/generators/win32/msbuild_objectmodel.cpp
@@ -0,0 +1,1940 @@
+/****************************************************************************
+**
+** 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 "msvc_objectmodel.h"
+#include "msbuild_objectmodel.h"
+#include "msvc_vcproj.h"
+#include "msvc_vcxproj.h"
+#include <qstringlist.h>
+#include <qfileinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+// XML Tags ---------------------------------------------------------
+const char _CLCompile[] = "ClCompile";
+const char _ItemGroup[] = "ItemGroup";
+const char _Link[] = "Link";
+const char _Midl[] = "Midl";
+const char _ResourceCompile[] = "ResourceCompile";
+
+// XML Properties ---------------------------------------------------
+const char _AddModuleNamesToAssembly[] = "AddModuleNamesToAssembly";
+const char _AdditionalDependencies[] = "AdditionalDependencies";
+const char _AdditionalIncludeDirectories[] = "AdditionalIncludeDirectories";
+const char _AdditionalLibraryDirectories[] = "AdditionalLibraryDirectories";
+const char _AdditionalManifestDependencies[] = "AdditionalManifestDependencies";
+const char _AdditionalOptions[] = "AdditionalOptions";
+const char _AdditionalUsingDirectories[] = "AdditionalUsingDirectories";
+const char _AllowIsolation[] = "AllowIsolation";
+const char _AlwaysAppend[] = "AlwaysAppend";
+const char _ApplicationConfigurationMode[] = "ApplicationConfigurationMode";
+const char _AssemblerListingLocation[] = "AssemblerListingLocation";
+const char _AssemblerOutput[] = "AssemblerOutput";
+const char _AssemblyDebug[] = "AssemblyDebug";
+const char _AssemblyLinkResource[] = "AssemblyLinkResource";
+const char _ATLMinimizesCRunTimeLibraryUsage[] = "ATLMinimizesCRunTimeLibraryUsage";
+const char _BaseAddress[] = "BaseAddress";
+const char _BasicRuntimeChecks[] = "BasicRuntimeChecks";
+const char _BrowseInformation[] = "BrowseInformation";
+const char _BrowseInformationFile[] = "BrowseInformationFile";
+const char _BufferSecurityCheck[] = "BufferSecurityCheck";
+const char _BuildBrowserInformation[] = "BuildBrowserInformation";
+const char _CallingConvention[] = "CallingConvention";
+const char _CharacterSet[] = "CharacterSet";
+const char _ClientStubFile[] = "ClientStubFile";
+const char _CLRImageType[] = "CLRImageType";
+const char _CLRSupportLastError[] = "CLRSupportLastError";
+const char _CLRThreadAttribute[] = "CLRThreadAttribute";
+const char _CLRUnmanagedCodeCheck[] = "CLRUnmanagedCodeCheck";
+const char _Command[] = "Command";
+const char _CompileAs[] = "CompileAs";
+const char _CompileAsManaged[] = "CompileAsManaged";
+const char _ConfigurationType[] = "ConfigurationType";
+const char _CPreprocessOptions[] = "CPreprocessOptions";
+const char _CreateHotpatchableImage[] = "CreateHotpatchableImage";
+const char _CreateHotPatchableImage[] = "CreateHotPatchableImage";
+const char _Culture[] = "Culture";
+const char _DataExecutionPrevention[] = "DataExecutionPrevention";
+const char _DebugInformationFormat[] = "DebugInformationFormat";
+const char _DefaultCharType[] = "DefaultCharType";
+const char _DelayLoadDLLs[] = "DelayLoadDLLs";
+const char _DelaySign[] = "DelaySign";
+const char _DeleteExtensionsOnClean[] = "DeleteExtensionsOnClean";
+const char _DisableLanguageExtensions[] = "DisableLanguageExtensions";
+const char _DisableSpecificWarnings[] = "DisableSpecificWarnings";
+const char _DisplayLibrary[] = "DisplayLibrary";
+const char _DLLDataFileName[] = "DLLDataFileName";
+const char _EmbedManagedResourceFile[] = "EmbedManagedResourceFile";
+const char _EnableCOMDATFolding[] = "EnableCOMDATFolding";
+const char _EnableUAC[] = "EnableUAC";
+const char _EnableErrorChecks[] = "EnableErrorChecks";
+const char _EnableEnhancedInstructionSet[] = "EnableEnhancedInstructionSet";
+const char _EnableFiberSafeOptimizations[] = "EnableFiberSafeOptimizations";
+const char _EnablePREfast[] = "EnablePREfast";
+const char _EntryPointSymbol[] = "EntryPointSymbol";
+const char _ErrorCheckAllocations[] = "ErrorCheckAllocations";
+const char _ErrorCheckBounds[] = "ErrorCheckBounds";
+const char _ErrorCheckEnumRange[] = "ErrorCheckEnumRange";
+const char _ErrorCheckRefPointers[] = "ErrorCheckRefPointers";
+const char _ErrorCheckStubData[] = "ErrorCheckStubData";
+const char _ErrorReporting[] = "ErrorReporting";
+const char _ExceptionHandling[] = "ExceptionHandling";
+const char _ExpandAttributedSource[] = "ExpandAttributedSource";
+const char _ExportNamedFunctions[] = "ExportNamedFunctions";
+const char _FavorSizeOrSpeed[] = "FavorSizeOrSpeed";
+const char _FloatingPointModel[] = "FloatingPointModel";
+const char _FloatingPointExceptions[] = "FloatingPointExceptions";
+const char _ForceConformanceInForLoopScope[] = "ForceConformanceInForLoopScope";
+const char _ForceSymbolReferences[] = "ForceSymbolReferences";
+const char _ForcedIncludeFiles[] = "ForcedIncludeFiles";
+const char _ForcedUsingFiles[] = "ForcedUsingFiles";
+const char _FunctionLevelLinking[] = "FunctionLevelLinking";
+const char _FunctionOrder[] = "FunctionOrder";
+const char _GenerateClientFiles[] = "GenerateClientFiles";
+const char _GenerateDebugInformation[] = "GenerateDebugInformation";
+const char _GenerateManifest[] = "GenerateManifest";
+const char _GenerateMapFile[] = "GenerateMapFile";
+const char _GenerateServerFiles[] = "GenerateServerFiles";
+const char _GenerateStublessProxies[] = "GenerateStublessProxies";
+const char _GenerateTypeLibrary[] = "GenerateTypeLibrary";
+const char _GenerateXMLDocumentationFiles[] = "GenerateXMLDocumentationFiles";
+const char _HeaderFileName[] = "HeaderFileName";
+const char _HeapCommitSize[] = "HeapCommitSize";
+const char _HeapReserveSize[] = "HeapReserveSize";
+const char _IgnoreAllDefaultLibraries[] = "IgnoreAllDefaultLibraries";
+const char _IgnoreEmbeddedIDL[] = "IgnoreEmbeddedIDL";
+const char _IgnoreImportLibrary[] = "IgnoreImportLibrary";
+const char _IgnoreSpecificDefaultLibraries[] = "IgnoreSpecificDefaultLibraries";
+const char _IgnoreStandardIncludePath[] = "IgnoreStandardIncludePath";
+const char _ImportLibrary[] = "ImportLibrary";
+const char _InlineFunctionExpansion[] = "InlineFunctionExpansion";
+const char _IntrinsicFunctions[] = "IntrinsicFunctions";
+const char _InterfaceIdentifierFileName[] = "InterfaceIdentifierFileName";
+const char _IntermediateDirectory[] = "IntermediateDirectory";
+const char _KeyContainer[] = "KeyContainer";
+const char _KeyFile[] = "KeyFile";
+const char _LargeAddressAware[] = "LargeAddressAware";
+const char _LinkDLL[] = "LinkDLL";
+const char _LinkErrorReporting[] = "LinkErrorReporting";
+const char _LinkIncremental[] = "LinkIncremental";
+const char _LinkStatus[] = "LinkStatus";
+const char _LinkTimeCodeGeneration[] = "LinkTimeCodeGeneration";
+const char _LocaleID[] = "LocaleID";
+const char _ManifestFile[] = "ManifestFile";
+const char _MapExports[] = "MapExports";
+const char _MapFileName[] = "MapFileName";
+const char _MergedIDLBaseFileName[] = "MergedIDLBaseFileName";
+const char _MergeSections[] = "MergeSections";
+const char _Message[] = "Message";
+const char _MidlCommandFile[] = "MidlCommandFile";
+const char _MinimalRebuild[] = "MinimalRebuild";
+const char _MkTypLibCompatible[] = "MkTypLibCompatible";
+const char _ModuleDefinitionFile[] = "ModuleDefinitionFile";
+const char _MultiProcessorCompilation[] = "MultiProcessorCompilation";
+const char _Name[] = "Name";
+const char _NoEntryPoint[] = "NoEntryPoint";
+const char _NullTerminateStrings[] = "NullTerminateStrings";
+const char _ObjectFiles[] = "ObjectFiles";
+const char _ObjectFileName[] = "ObjectFileName";
+const char _OmitDefaultLibName[] = "OmitDefaultLibName";
+const char _OmitFramePointers[] = "OmitFramePointers";
+const char _OpenMPSupport[] = "OpenMPSupport";
+const char _Optimization[] = "Optimization";
+const char _OptimizeReferences[] = "OptimizeReferences";
+const char _OutputDirectory[] = "OutputDirectory";
+const char _OutputFile[] = "OutputFile";
+const char _PrecompiledHeader[] = "PrecompiledHeader";
+const char _PrecompiledHeaderFile[] = "PrecompiledHeaderFile";
+const char _PrecompiledHeaderOutputFile[] = "PrecompiledHeaderOutputFile";
+const char _PreprocessorDefinitions[] = "PreprocessorDefinitions";
+const char _PreprocessKeepComments[] = "PreprocessKeepComments";
+const char _PreprocessOutputPath[] = "PreprocessOutputPath";
+const char _PreprocessSuppressLineNumbers[] = "PreprocessSuppressLineNumbers";
+const char _PreprocessToFile[] = "PreprocessToFile";
+const char _PreventDllBinding[] = "PreventDllBinding";
+const char _PrimaryOutput[] = "PrimaryOutput";
+const char _ProcessorNumber[] = "ProcessorNumber";
+const char _ProgramDatabase[] = "ProgramDatabase";
+const char _ProgramDataBaseFileName[] = "ProgramDataBaseFileName";
+const char _ProgramDatabaseFile[] = "ProgramDatabaseFile";
+const char _ProxyFileName[] = "ProxyFileName";
+const char _RandomizedBaseAddress[] = "RandomizedBaseAddress";
+const char _RedirectOutputAndErrors[] = "RedirectOutputAndErrors";
+const char _RegisterOutput[] = "RegisterOutput";
+const char _RemoveObjects[] = "RemoveObjects";
+const char _ResourceOutputFileName[] = "ResourceOutputFileName";
+const char _RuntimeLibrary[] = "RuntimeLibrary";
+const char _RuntimeTypeInfo[] = "RuntimeTypeInfo";
+const char _SectionAlignment[] = "SectionAlignment";
+const char _ServerStubFile[] = "ServerStubFile";
+const char _SetChecksum[] = "SetChecksum";
+const char _ShowIncludes[] = "ShowIncludes";
+const char _ShowProgress[] = "ShowProgress";
+const char _SmallerTypeCheck[] = "SmallerTypeCheck";
+const char _StackCommitSize[] = "StackCommitSize";
+const char _StackReserveSize[] = "StackReserveSize";
+const char _StringPooling[] = "StringPooling";
+const char _StripPrivateSymbols[] = "StripPrivateSymbols";
+const char _StructMemberAlignment[] = "StructMemberAlignment";
+const char _SubSystem[] = "SubSystem";
+const char _SupportNobindOfDelayLoadedDLL[] = "SupportNobindOfDelayLoadedDLL";
+const char _SupportUnloadOfDelayLoadedDLL[] = "SupportUnloadOfDelayLoadedDLL";
+const char _SuppressCompilerWarnings[] = "SuppressCompilerWarnings";
+const char _SuppressStartupBanner[] = "SuppressStartupBanner";
+const char _SwapRunFromCD[] = "SwapRunFromCD";
+const char _SwapRunFromNet[] = "SwapRunFromNet";
+const char _TargetEnvironment[] = "TargetEnvironment";
+const char _TargetMachine[] = "TargetMachine";
+const char _TerminalServerAware[] = "TerminalServerAware";
+const char _TrackerLogDirectory[] = "TrackerLogDirectory";
+const char _TreatLibWarningAsErrors[] = "TreatLibWarningAsErrors";
+const char _TreatLinkerWarningAsErrors[] = "TreatLinkerWarningAsErrors";
+const char _TreatSpecificWarningsAsErrors[] = "TreatSpecificWarningsAsErrors";
+const char _TreatWarningAsError[] = "TreatWarningAsError";
+const char _TreatWChar_tAsBuiltInType[] = "TreatWChar_tAsBuiltInType";
+const char _TurnOffAssemblyGeneration[] = "TurnOffAssemblyGeneration";
+const char _TypeLibFormat[] = "TypeLibFormat";
+const char _TypeLibraryFile[] = "TypeLibraryFile";
+const char _TypeLibraryName[] = "TypeLibraryName";
+const char _TypeLibraryResourceID[] = "TypeLibraryResourceID";
+const char _UACExecutionLevel[] = "UACExecutionLevel";
+const char _UACUIAccess[] = "UACUIAccess";
+const char _UndefineAllPreprocessorDefinitions[]= "UndefineAllPreprocessorDefinitions";
+const char _UndefinePreprocessorDefinitions[] = "UndefinePreprocessorDefinitions";
+const char _UseFullPaths[] = "UseFullPaths";
+const char _UseOfATL[] = "UseOfATL";
+const char _UseOfMfc[] = "UseOfMfc";
+const char _UseUnicodeForAssemblerListing[] = "UseUnicodeForAssemblerListing";
+const char _ValidateAllParameters[] = "ValidateAllParameters";
+const char _VCCustomBuildTool[] = "VCCustomBuildTool";
+const char _Verbose[] = "Verbose";
+const char _Version[] = "Version";
+const char _WarnAsError[] = "WarnAsError";
+const char _WarningLevel[] = "WarningLevel";
+const char _WholeProgramOptimization[] = "WholeProgramOptimization";
+const char _XMLDocumentationFileName[] = "XMLDocumentationFileName";
+
+
+// XmlOutput stream functions ------------------------------
+inline XmlOutput::xml_output attrTagT(const char *name, const triState v)
+{
+ if(v == unset)
+ return noxml();
+ return tagValue(name, (v == _True ? "true" : "false"));
+}
+
+inline XmlOutput::xml_output attrTagL(const char *name, qint64 v)
+{
+ return tagValue(name, QString::number(v));
+}
+
+/*ifNot version*/
+inline XmlOutput::xml_output attrTagL(const char *name, qint64 v, qint64 ifn)
+{
+ if (v == ifn)
+ return noxml();
+ return tagValue(name, QString::number(v));
+}
+
+inline XmlOutput::xml_output attrTagS(const char *name, const QString &v)
+{
+ if(v.isEmpty())
+ return noxml();
+ return tagValue(name, v);
+}
+
+inline XmlOutput::xml_output attrTagX(const char *name, const QStringList &v, const char *s = ",")
+{
+ if(v.isEmpty())
+ return noxml();
+ QStringList temp = v;
+ temp.append(QString("%(%1)").arg(name));
+ return tagValue(name, temp.join(s));
+}
+
+inline XmlOutput::xml_output valueTagX(const QStringList &v, const char *s = " ")
+{
+ if(v.isEmpty())
+ return noxml();
+ return valueTag(v.join(s));
+}
+
+inline XmlOutput::xml_output valueTagDefX(const QStringList &v, const QString &tagName, const char *s = " ")
+{
+ if(v.isEmpty())
+ return noxml();
+ QStringList temp = v;
+ temp.append(QString("%(%1)").arg(tagName));
+ return valueTag(temp.join(s));
+}
+
+inline XmlOutput::xml_output valueTagT( const triState v)
+{
+ if(v == unset)
+ return noxml();
+ return valueTag(v == _True ? "true" : "false");
+}
+
+static QString vcxCommandSeparator()
+{
+ // MSBuild puts the contents of the custom commands into a batch file and calls it.
+ // As we want every sub-command to be error-checked (as is done by makefile-based
+ // backends), we insert the checks ourselves, using the undocumented jump target.
+ static QString cmdSep =
+ QLatin1String("&#x000D;&#x000A;if errorlevel 1 goto VCEnd&#x000D;&#x000A;");
+ return cmdSep;
+}
+
+// Tree file generation ---------------------------------------------
+void XTreeNode::generateXML(XmlOutput &xml, XmlOutput &xmlFilter, const QString &tagName, VCProject &tool, const QString &filter) {
+
+ if (children.size()) {
+ // Filter
+ QString tempFilterName;
+ ChildrenMap::ConstIterator it, end = children.constEnd();
+ if (!tagName.isEmpty()) {
+ tempFilterName.append(filter);
+ tempFilterName.append("\\");
+ tempFilterName.append(tagName);
+ xmlFilter << tag(_ItemGroup);
+ xmlFilter << tag("Filter")
+ << attrTag("Include", tempFilterName)
+ << closetag();
+ xmlFilter << closetag();
+ }
+ // First round, do nested filters
+ for (it = children.constBegin(); it != end; ++it)
+ if ((*it)->children.size())
+ {
+ if ( !tempFilterName.isEmpty() )
+ (*it)->generateXML(xml, xmlFilter, it.key(), tool, tempFilterName);
+ else
+ (*it)->generateXML(xml, xmlFilter, it.key(), tool, filter);
+ }
+ // Second round, do leafs
+ for (it = children.constBegin(); it != end; ++it)
+ if (!(*it)->children.size())
+ {
+ if ( !tempFilterName.isEmpty() )
+ (*it)->generateXML(xml, xmlFilter, it.key(), tool, tempFilterName);
+ else
+ (*it)->generateXML(xml, xmlFilter, it.key(), tool, filter);
+ }
+ } else {
+ // Leaf
+ xml << tag(_ItemGroup);
+ xmlFilter << tag(_ItemGroup);
+ VCXProjectWriter::outputFileConfigs(tool, xml, xmlFilter, info, filter);
+ xmlFilter << closetag();
+ xml << closetag();
+ }
+}
+
+// Flat file generation ---------------------------------------------
+void XFlatNode::generateXML(XmlOutput &xml, XmlOutput &xmlFilter, const QString &/*tagName*/, VCProject &tool, const QString &filter) {
+ if (children.size()) {
+ ChildrenMapFlat::ConstIterator it = children.constBegin();
+ ChildrenMapFlat::ConstIterator end = children.constEnd();
+ xml << tag(_ItemGroup);
+ xmlFilter << tag(_ItemGroup);
+ for (; it != end; ++it) {
+ VCXProjectWriter::outputFileConfigs(tool, xml, xmlFilter, (*it), filter);
+ }
+ xml << closetag();
+ xmlFilter << closetag();
+ }
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, VCProjectSingleConfig &tool)
+{
+ xml.setIndentString(" ");
+
+ xml << decl("1.0", "utf-8")
+ << tag("Project")
+ << attrTag("DefaultTargets","Build")
+ << attrTag("ToolsVersion", "4.0")
+ << attrTag("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003")
+ << tag("ItemGroup")
+ << attrTag("Label", "ProjectConfigurations");
+
+ xml << tag("ProjectConfiguration")
+ << attrTag("Include" , tool.Configuration.Name)
+ << tagValue("Configuration", tool.Configuration.ConfigurationName)
+ << tagValue("Platform", tool.PlatformName)
+ << closetag();
+
+ xml << closetag()
+ << tag("PropertyGroup")
+ << attrTag("Label", "Globals")
+ << tagValue("ProjectGuid", tool.ProjectGUID)
+ << tagValue("RootNamespace", tool.Name)
+ << tagValue("Keyword", tool.Keyword)
+ << closetag();
+
+ // config part.
+ xml << import("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
+
+ write(xml, tool.Configuration);
+
+ xml << import("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
+
+ // Extension settings
+ xml << tag("ImportGroup")
+ << attrTag("Label", "ExtensionSettings")
+ << closetag();
+
+ // PropertySheets
+ xml << tag("ImportGroup")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Configuration.Name))
+ << attrTag("Label", "PropertySheets");
+
+ xml << tag("Import")
+ << attrTag("Project", "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props")
+ << attrTag("Condition", "exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')")
+ << closetag()
+ << closetag();
+
+
+ // UserMacros
+ xml << tag("PropertyGroup")
+ << attrTag("Label", "UserMacros")
+ << closetag();
+
+ xml << tag("PropertyGroup");
+
+ if ( !tool.Configuration.OutputDirectory.isEmpty() ) {
+ xml<< tag("OutDir")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Configuration.Name))
+ << valueTag(tool.Configuration.OutputDirectory);
+ }
+ if ( !tool.Configuration.IntermediateDirectory.isEmpty() ) {
+ xml<< tag("IntDir")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Configuration.Name))
+ << valueTag(tool.Configuration.IntermediateDirectory);
+ }
+ if ( !tool.Configuration.PrimaryOutput.isEmpty() ) {
+ xml<< tag("TargetName")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Configuration.Name))
+ << valueTag(tool.Configuration.PrimaryOutput);
+ }
+
+ if ( tool.Configuration.linker.IgnoreImportLibrary != unset) {
+ xml<< tag("IgnoreImportLibrary")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Configuration.Name))
+ << valueTagT(tool.Configuration.linker.IgnoreImportLibrary);
+ }
+
+ if ( tool.Configuration.linker.LinkIncremental != linkIncrementalDefault) {
+ const triState ts = (tool.Configuration.linker.LinkIncremental == linkIncrementalYes ? _True : _False);
+ xml<< tag("LinkIncremental")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Configuration.Name))
+ << valueTagT(ts);
+ }
+
+ if ( tool.Configuration.preBuild.ExcludedFromBuild != unset )
+ {
+ xml<< tag("PreBuildEventUseInBuild")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Configuration.Name))
+ << valueTagT(!tool.Configuration.preBuild.ExcludedFromBuild);
+ }
+
+ if ( tool.Configuration.preLink.ExcludedFromBuild != unset )
+ {
+ xml<< tag("PreLinkEventUseInBuild")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Configuration.Name))
+ << valueTagT(!tool.Configuration.preLink.ExcludedFromBuild);
+ }
+
+ if ( tool.Configuration.postBuild.ExcludedFromBuild != unset )
+ {
+ xml<< tag("PostBuildEventUseInBuild")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Configuration.Name))
+ << valueTagT(!tool.Configuration.postBuild.ExcludedFromBuild);
+ }
+ xml << closetag();
+
+ xml << tag("ItemDefinitionGroup")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Configuration.Name));
+
+ // ClCompile
+ write(xml, tool.Configuration.compiler);
+
+ // Link
+ write(xml, tool.Configuration.linker);
+
+ // Midl
+ write(xml, tool.Configuration.idl);
+
+ // ResourceCompiler
+ write(xml, tool.Configuration.resource);
+
+ // Post build event
+ if ( tool.Configuration.postBuild.ExcludedFromBuild != unset )
+ write(xml, tool.Configuration.postBuild);
+
+ // Pre build event
+ if ( tool.Configuration.preBuild.ExcludedFromBuild != unset )
+ write(xml, tool.Configuration.preBuild);
+
+ // Pre link event
+ if ( tool.Configuration.preLink.ExcludedFromBuild != unset )
+ write(xml, tool.Configuration.preLink);
+
+ xml << closetag();
+
+ QFile filterFile;
+ filterFile.setFileName(Option::output.fileName().append(".filters"));
+ filterFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
+ QTextStream ts(&filterFile);
+ XmlOutput xmlFilter(ts, XmlOutput::NoConversion);
+
+ xmlFilter.setIndentString(" ");
+
+ xmlFilter << decl("1.0", "utf-8")
+ << tag("Project")
+ << attrTag("ToolsVersion", "4.0")
+ << attrTag("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
+
+ xmlFilter << tag("ItemGroup");
+
+ VCProject tempProj;
+ tempProj.SingleProjects += tool;
+
+ addFilters(tempProj, xmlFilter, "Form Files");
+ addFilters(tempProj, xmlFilter, "Generated Files");
+ addFilters(tempProj, xmlFilter, "Header Files");
+ addFilters(tempProj, xmlFilter, "LexYacc Files");
+ addFilters(tempProj, xmlFilter, "Resource Files");
+ addFilters(tempProj, xmlFilter, "Source Files");
+ addFilters(tempProj, xmlFilter, "Translation Files");
+ xmlFilter << closetag();
+
+ outputFilter(tempProj, xml, xmlFilter, "Source Files");
+ outputFilter(tempProj, xml, xmlFilter, "Header Files");
+ outputFilter(tempProj, xml, xmlFilter, "Generated Files");
+ outputFilter(tempProj, xml, xmlFilter, "LexYacc Files");
+ outputFilter(tempProj, xml, xmlFilter, "Translation Files");
+ outputFilter(tempProj, xml, xmlFilter, "Form Files");
+ outputFilter(tempProj, xml, xmlFilter, "Resource Files");
+
+ for (int x = 0; x < tempProj.ExtraCompilers.count(); ++x) {
+ outputFilter(tempProj, xml, xmlFilter, tempProj.ExtraCompilers.at(x));
+ }
+
+ xml << import("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets");
+
+ xml << tag("ImportGroup")
+ << attrTag("Label", "ExtensionTargets")
+ << closetag();
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, VCProject &tool)
+{
+ if (tool.SingleProjects.count() == 0) {
+ warn_msg(WarnLogic, "Generator: .NET: no single project in merge project, no output");
+ return;
+ }
+
+ xml.setIndentString(" ");
+
+ xml << decl("1.0", "utf-8")
+ << tag("Project")
+ << attrTag("DefaultTargets","Build")
+ << attrTag("ToolsVersion", "4.0")
+ << attrTag("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003")
+ << tag("ItemGroup")
+ << attrTag("Label", "ProjectConfigurations");
+
+ for (int i = 0; i < tool.SingleProjects.count(); ++i) {
+ xml << tag("ProjectConfiguration")
+ << attrTag("Include" , tool.SingleProjects.at(i).Configuration.Name)
+ << tagValue("Configuration", tool.SingleProjects.at(i).Configuration.ConfigurationName)
+ << tagValue("Platform", tool.SingleProjects.at(i).PlatformName)
+ << closetag();
+ }
+
+ xml << closetag()
+ << tag("PropertyGroup")
+ << attrTag("Label", "Globals")
+ << tagValue("ProjectGuid", tool.ProjectGUID)
+ << tagValue("RootNamespace", tool.Name)
+ << tagValue("Keyword", tool.Keyword)
+ << closetag();
+
+ // config part.
+ xml << import("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
+ for (int i = 0; i < tool.SingleProjects.count(); ++i)
+ write(xml, tool.SingleProjects.at(i).Configuration);
+ xml << import("Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
+
+ // Extension settings
+ xml << tag("ImportGroup")
+ << attrTag("Label", "ExtensionSettings")
+ << closetag();
+
+ // PropertySheets
+ for (int i = 0; i < tool.SingleProjects.count(); ++i) {
+ xml << tag("ImportGroup")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.SingleProjects.at(i).Configuration.Name))
+ << attrTag("Label", "PropertySheets");
+
+ xml << tag("Import")
+ << attrTag("Project", "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props")
+ << attrTag("Condition", "exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')")
+ << closetag()
+ << closetag();
+ }
+
+ // UserMacros
+ xml << tag("PropertyGroup")
+ << attrTag("Label", "UserMacros")
+ << closetag();
+
+ xml << tag("PropertyGroup");
+ for (int i = 0; i < tool.SingleProjects.count(); ++i) {
+
+ if ( !tool.SingleProjects.at(i).Configuration.OutputDirectory.isEmpty() ) {
+ xml << tag("OutDir")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.SingleProjects.at(i).Configuration.Name))
+ << valueTag(tool.SingleProjects.at(i).Configuration.OutputDirectory);
+ }
+ if ( !tool.SingleProjects.at(i).Configuration.IntermediateDirectory.isEmpty() ) {
+ xml << tag("IntDir")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.SingleProjects.at(i).Configuration.Name))
+ << valueTag(tool.SingleProjects.at(i).Configuration.IntermediateDirectory);
+ }
+ if ( !tool.SingleProjects.at(i).Configuration.PrimaryOutput.isEmpty() ) {
+ xml << tag("TargetName")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.SingleProjects.at(i).Configuration.Name))
+ << valueTag(tool.SingleProjects.at(i).Configuration.PrimaryOutput);
+ }
+
+ if ( tool.SingleProjects.at(i).Configuration.linker.IgnoreImportLibrary != unset) {
+ xml << tag("IgnoreImportLibrary")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.SingleProjects.at(i).Configuration.Name))
+ << valueTagT(tool.SingleProjects.at(i).Configuration.linker.IgnoreImportLibrary);
+ }
+
+ if ( tool.SingleProjects.at(i).Configuration.linker.LinkIncremental != unset) {
+ const triState ts = (tool.SingleProjects.at(i).Configuration.linker.LinkIncremental == linkIncrementalYes ? _True : _False);
+ xml << tag("LinkIncremental")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.SingleProjects.at(i).Configuration.Name))
+ << valueTagT(ts);
+ }
+
+ if ( tool.SingleProjects.at(i).Configuration.preBuild.ExcludedFromBuild != unset )
+ {
+ xml << tag("PreBuildEventUseInBuild")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.SingleProjects.at(i).Configuration.Name))
+ << valueTagT(!tool.SingleProjects.at(i).Configuration.preBuild.ExcludedFromBuild);
+ }
+
+ if ( tool.SingleProjects.at(i).Configuration.preLink.ExcludedFromBuild != unset )
+ {
+ xml << tag("PreLinkEventUseInBuild")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.SingleProjects.at(i).Configuration.Name))
+ << valueTagT(!tool.SingleProjects.at(i).Configuration.preLink.ExcludedFromBuild);
+ }
+
+ if ( tool.SingleProjects.at(i).Configuration.postBuild.ExcludedFromBuild != unset )
+ {
+ xml << tag("PostBuildEventUseInBuild")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.SingleProjects.at(i).Configuration.Name))
+ << valueTagT(!tool.SingleProjects.at(i).Configuration.postBuild.ExcludedFromBuild);
+ }
+ }
+ xml << closetag();
+
+ for (int i = 0; i < tool.SingleProjects.count(); ++i) {
+ xml << tag("ItemDefinitionGroup")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.SingleProjects.at(i).Configuration.Name));
+
+ // ClCompile
+ write(xml, tool.SingleProjects.at(i).Configuration.compiler);
+
+ // Link
+ write(xml, tool.SingleProjects.at(i).Configuration.linker);
+
+ // Midl
+ write(xml, tool.SingleProjects.at(i).Configuration.idl);
+
+ // ResourceCompiler
+ write(xml, tool.SingleProjects.at(i).Configuration.resource);
+
+ // Post build event
+ if ( tool.SingleProjects.at(i).Configuration.postBuild.ExcludedFromBuild != unset )
+ write(xml, tool.SingleProjects.at(i).Configuration.postBuild);
+
+ // Pre build event
+ if ( tool.SingleProjects.at(i).Configuration.preBuild.ExcludedFromBuild != unset )
+ write(xml, tool.SingleProjects.at(i).Configuration.preBuild);
+
+ // Pre link event
+ if ( tool.SingleProjects.at(i).Configuration.preLink.ExcludedFromBuild != unset )
+ write(xml, tool.SingleProjects.at(i).Configuration.preLink);
+
+ xml << closetag();
+ }
+
+ // The file filters are added in a separate file for MSBUILD.
+ QFile filterFile;
+ filterFile.setFileName(Option::output.fileName().append(".filters"));
+ filterFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
+ QTextStream ts(&filterFile);
+ XmlOutput xmlFilter(ts, XmlOutput::NoConversion);
+
+ xmlFilter.setIndentString(" ");
+
+ xmlFilter << decl("1.0", "utf-8")
+ << tag("Project")
+ << attrTag("ToolsVersion", "4.0")
+ << attrTag("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
+
+ xmlFilter << tag("ItemGroup");
+
+ addFilters(tool, xmlFilter, "Form Files");
+ addFilters(tool, xmlFilter, "Generated Files");
+ addFilters(tool, xmlFilter, "Header Files");
+ addFilters(tool, xmlFilter, "LexYacc Files");
+ addFilters(tool, xmlFilter, "Resource Files");
+ addFilters(tool, xmlFilter, "Source Files");
+ addFilters(tool, xmlFilter, "Translation Files");
+ xmlFilter << closetag();
+
+ outputFilter(tool, xml, xmlFilter, "Source Files");
+ outputFilter(tool, xml, xmlFilter, "Header Files");
+ outputFilter(tool, xml, xmlFilter, "Generated Files");
+ outputFilter(tool, xml, xmlFilter, "LexYacc Files");
+ outputFilter(tool, xml, xmlFilter, "Translation Files");
+ outputFilter(tool, xml, xmlFilter, "Form Files");
+ outputFilter(tool, xml, xmlFilter, "Resource Files");
+ for (int x = 0; x < tool.ExtraCompilers.count(); ++x) {
+ outputFilter(tool, xml, xmlFilter, tool.ExtraCompilers.at(x));
+ }
+ outputFilter(tool, xml, xmlFilter, "Root Files");
+
+ xml << import("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets");
+
+ xml << tag("ImportGroup")
+ << attrTag("Label", "ExtensionTargets")
+ << closetag();
+}
+
+static inline QString toString(asmListingOption option)
+{
+ switch (option) {
+ case asmListingAsmMachine:
+ return "AssemblyAndMachineCode";
+ case asmListingAsmMachineSrc:
+ return "All";
+ case asmListingAsmSrc:
+ return "AssemblyAndSourceCode";
+ case asmListingAssemblyOnly:
+ return "AssemblyCode";
+ }
+ return QString();
+}
+
+static inline QString toString(basicRuntimeCheckOption option)
+{
+ switch (option) {
+ case runtimeBasicCheckNone:
+ return "";
+ case runtimeCheckStackFrame:
+ return "StackFrameRuntimeCheck";
+ case runtimeCheckUninitVariables:
+ return "UninitializedLocalUsageCheck";
+ case runtimeBasicCheckAll:
+ return "EnableFastChecks";
+ }
+ return QString();
+}
+
+static inline QString toString(callingConventionOption option)
+{
+ switch (option) {
+ case callConventionCDecl:
+ return "Cdecl";
+ case callConventionFastCall:
+ return "FastCall";
+ case callConventionStdCall:
+ return "StdCall";
+ }
+ return QString();
+}
+
+static inline QString toString(CompileAsOptions option)
+{
+ switch (option) {
+ case compileAsC:
+ return "CompileAsC";
+ case compileAsCPlusPlus:
+ return "CompileAsCpp";
+ }
+ return QString();
+}
+
+static inline QString toString(compileAsManagedOptions option)
+{
+ switch (option) {
+ case managedAssembly:
+ return "true";
+ case managedAssemblyPure:
+ return "Safe";
+ case managedAssemblyOldSyntax:
+ return "OldSyntax";
+ }
+ return QString();
+}
+
+static inline QString toString(debugOption option)
+{
+ switch (option) {
+ case debugOldStyleInfo:
+ return "OldStyle";
+ case debugEditAndContinue:
+ return "EditAndContinue";
+ case debugEnabled:
+ return "ProgramDatabase";
+ }
+ return QString();
+}
+
+static inline QString toString(enhancedInstructionSetOption option)
+{
+ switch (option) {
+ case archSSE:
+ return "StreamingSIMDExtensions";
+ case archSSE2:
+ return "StreamingSIMDExtensions2";
+ }
+ return QString();
+}
+
+static inline QString toString(exceptionHandling option)
+{
+ switch (option) {
+ case ehNone:
+ return "false";
+ case ehNoSEH:
+ return "Sync";
+ case ehSEH:
+ return "Async";
+ }
+ return QString();
+}
+
+static inline QString toString(favorSizeOrSpeedOption option)
+{
+ switch (option) {
+ case favorSize:
+ return "Size";
+ case favorSpeed:
+ return "Speed";
+ }
+ return QString();
+}
+
+static inline QString toString(floatingPointModel option)
+{
+ switch (option) {
+ case floatingPointFast:
+ return "Fast";
+ case floatingPointPrecise:
+ return "Precise";
+ case floatingPointStrict:
+ return "Strict";
+ }
+ return QString();
+}
+
+static inline QString toString(inlineExpansionOption option)
+{
+ switch (option) {
+ case expandDisable:
+ return "Disabled";
+ case expandOnlyInline:
+ return "OnlyExplicitInline";
+ case expandAnySuitable:
+ return "AnySuitable";
+ }
+ return QString();
+}
+
+static inline QString toString(optimizeOption option)
+{
+ switch (option) {
+ case optimizeMinSpace:
+ return "MinSpace";
+ case optimizeMaxSpeed:
+ return "MaxSpeed";
+ }
+ return QString();
+}
+
+static inline QString toString(pchOption option)
+{
+ switch (option) {
+ case pchNone:
+ return "NotUsing";
+ case pchCreateUsingSpecific:
+ return "Create";
+ case pchUseUsingSpecific:
+ return "Use";
+ }
+ return QString();
+}
+
+static inline QString toString(runtimeLibraryOption option)
+{
+ switch (option) {
+ case rtMultiThreaded:
+ return "MultiThreaded";
+ case rtMultiThreadedDLL:
+ return "MultiThreadedDLL";
+ case rtMultiThreadedDebug:
+ return "MultiThreadedDebug";
+ case rtMultiThreadedDebugDLL:
+ return "MultiThreadedDebugDLL";
+ }
+ return QString();
+}
+
+static inline QString toString(structMemberAlignOption option)
+{
+ switch (option) {
+ case alignSingleByte:
+ return "1Byte";
+ case alignTwoBytes:
+ return "2Bytes";
+ case alignFourBytes:
+ return "4Bytes";
+ case alignEightBytes:
+ return "8Bytes";
+ case alignSixteenBytes:
+ return "16Bytes";
+ }
+ return QString();
+}
+
+static inline QString toString(warningLevelOption option)
+{
+ switch (option) {
+ case warningLevel_0:
+ return "TurnOffAllWarnings";
+ case warningLevel_1:
+ return "Level1";
+ case warningLevel_2:
+ return "Level2";
+ case warningLevel_3:
+ return "Level3";
+ case warningLevel_4:
+ return "Level4";
+ }
+ return QString();
+}
+
+static inline QString toString(optLinkTimeCodeGenType option)
+{
+ switch (option) {
+ case optLTCGEnabled:
+ return "UseLinkTimeCodeGeneration";
+ case optLTCGInstrument:
+ return "PGInstrument";
+ case optLTCGOptimize:
+ return "PGOptimization";
+ case optLTCGUpdate:
+ return "PGUpdate";
+ }
+ return QString();
+}
+
+static inline QString toString(subSystemOption option)
+{
+ switch (option) {
+ case subSystemConsole:
+ return "Console";
+ case subSystemWindows:
+ return "Windows";
+ }
+ return QString();
+}
+
+static inline QString toString(machineTypeOption option)
+{
+ switch (option) {
+ case machineX86:
+ return "MachineX86";
+ case machineX64:
+ return "MachineX64";
+ }
+ return QString();
+}
+
+static inline QString toString(midlCharOption option)
+{
+ switch (option) {
+ case midlCharUnsigned:
+ return "Unsigned";
+ case midlCharSigned:
+ return "Signed";
+ case midlCharAscii7:
+ return "Ascii";
+ }
+ return QString();
+}
+
+static inline QString toString(midlErrorCheckOption option)
+{
+ switch (option) {
+ case midlDisableAll:
+ return "None";
+ case midlEnableAll:
+ return "All";
+ }
+ return QString();
+}
+
+static inline QString toString(midlStructMemberAlignOption option)
+{
+ switch (option) {
+ case midlAlignSingleByte:
+ return "1";
+ case midlAlignTwoBytes:
+ return "2";
+ case midlAlignFourBytes:
+ return "4";
+ case midlAlignEightBytes:
+ return "8";
+ case midlAlignSixteenBytes:
+ return "16";
+ }
+ return QString();
+}
+
+static inline QString toString(midlTargetEnvironment option)
+{
+ switch (option) {
+ case midlTargetWin32:
+ return "Win32";
+ case midlTargetWin64:
+ return "X64";
+ }
+ return QString();
+}
+
+static inline QString toString(midlWarningLevelOption option)
+{
+ switch (option) {
+ case midlWarningLevel_0:
+ return "0";
+ case midlWarningLevel_1:
+ return "1";
+ case midlWarningLevel_2:
+ return "2";
+ case midlWarningLevel_3:
+ return "3";
+ case midlWarningLevel_4:
+ return "4";
+ }
+ return QString();
+}
+
+static inline QString toString(enumResourceLangID option)
+{
+ if (option == 0)
+ return QString();
+ else
+ return QString::number(qlonglong(option));
+}
+
+static inline QString toString(charSet option)
+{
+ switch (option) {
+ case charSetNotSet:
+ return "NotSet";
+ case charSetUnicode:
+ return "Unicode";
+ case charSetMBCS:
+ return "MultiByte";
+ }
+ return QString();
+}
+
+static inline QString toString(ConfigurationTypes option)
+{
+ switch (option) {
+ case typeApplication:
+ return "Application";
+ case typeDynamicLibrary:
+ return "DynamicLibrary";
+ case typeStaticLibrary:
+ return "StaticLibrary";
+ }
+ return QString();
+}
+
+static inline QString toString(useOfATL option)
+{
+ switch (option) {
+ case useATLStatic:
+ return "Static";
+ case useATLDynamic:
+ return "Dynamic";
+ }
+ return QString();
+}
+
+static inline QString toString(useOfMfc option)
+{
+ switch (option) {
+ case useMfcStatic:
+ return "Static";
+ case useMfcDynamic:
+ return "Dynamic";
+ }
+ return QString();
+}
+
+static inline triState toTriState(browseInfoOption option)
+{
+ switch (option)
+ {
+ case brInfoNone:
+ return _False;
+ case brAllInfo:
+ case brNoLocalSymbols:
+ return _True;
+ }
+ return unset;
+}
+
+static inline triState toTriState(preprocessOption option)
+{
+ switch (option)
+ {
+ case preprocessNo:
+ return _False;
+ case preprocessNoLineNumbers:
+ case preprocessYes:
+ return _True;
+ }
+ return unset;
+}
+
+static inline triState toTriState(optFoldingType option)
+{
+ switch (option)
+ {
+ case optNoFolding:
+ return _False;
+ case optFolding:
+ return _True;
+ }
+ return unset;
+}
+
+static inline triState toTriState(addressAwarenessType option)
+{
+ switch (option)
+ {
+ case addrAwareDefault:
+ return unset;
+ case addrAwareNoLarge:
+ return _False;
+ case addrAwareLarge:
+ return _True;
+ }
+ return unset;
+}
+
+static inline triState toTriState(linkIncrementalType option)
+{
+ switch (option)
+ {
+ case linkIncrementalDefault:
+ return unset;
+ case linkIncrementalNo:
+ return _False;
+ case linkIncrementalYes:
+ return _True;
+ }
+ return unset;
+}
+
+static inline triState toTriState(linkProgressOption option)
+{
+ switch (option)
+ {
+ case linkProgressNotSet:
+ return unset;
+ case linkProgressAll:
+ case linkProgressLibs:
+ return _True;
+ }
+ return unset;
+}
+
+static inline triState toTriState(optRefType option)
+{
+ switch (option)
+ {
+ case optReferencesDefault:
+ return unset;
+ case optNoReferences:
+ return _False;
+ case optReferences:
+ return _True;
+ }
+ return unset;
+}
+
+static inline triState toTriState(termSvrAwarenessType option)
+{
+ switch (option)
+ {
+ case termSvrAwareDefault:
+ return unset;
+ case termSvrAwareNo:
+ return _False;
+ case termSvrAwareYes:
+ return _True;
+ }
+ return unset;
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, const VCCLCompilerTool &tool)
+{
+ xml
+ << tag(_CLCompile)
+ << attrTagX(_AdditionalIncludeDirectories, tool.AdditionalIncludeDirectories, ";")
+ << attrTagX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrTagX(_AdditionalUsingDirectories, tool.AdditionalUsingDirectories, ";")
+//unused << attrTagS(_AlwaysAppend, tool.AlwaysAppend)
+ << attrTagS(_AssemblerListingLocation, tool.AssemblerListingLocation)
+ << attrTagS(_AssemblerOutput, toString(tool.AssemblerOutput))
+ << attrTagS(_BasicRuntimeChecks, toString(tool.BasicRuntimeChecks))
+ << attrTagT(_BrowseInformation, toTriState(tool.BrowseInformation))
+ << attrTagS(_BrowseInformationFile, tool.BrowseInformationFile)
+ << attrTagT(_BufferSecurityCheck, tool.BufferSecurityCheck)
+ << attrTagS(_CallingConvention, toString(tool.CallingConvention))
+ << attrTagS(_CompileAs, toString(tool.CompileAs))
+ << attrTagS(_CompileAsManaged, toString(tool.CompileAsManaged))
+ << attrTagT(_CreateHotpatchableImage, tool.CreateHotpatchableImage)
+ << attrTagS(_DebugInformationFormat, toString(tool.DebugInformationFormat))
+ << attrTagT(_DisableLanguageExtensions, tool.DisableLanguageExtensions)
+ << attrTagX(_DisableSpecificWarnings, tool.DisableSpecificWarnings, ";")
+ << attrTagS(_EnableEnhancedInstructionSet, toString(tool.EnableEnhancedInstructionSet))
+ << attrTagT(_EnableFiberSafeOptimizations, tool.EnableFiberSafeOptimizations)
+ << attrTagT(_EnablePREfast, tool.EnablePREfast)
+ << attrTagS(_ErrorReporting, tool.ErrorReporting)
+ << attrTagS(_ExceptionHandling, toString(tool.ExceptionHandling))
+ << attrTagT(_ExpandAttributedSource, tool.ExpandAttributedSource)
+ << attrTagS(_FavorSizeOrSpeed, toString(tool.FavorSizeOrSpeed))
+ << attrTagT(_FloatingPointExceptions, tool.FloatingPointExceptions)
+ << attrTagS(_FloatingPointModel, toString(tool.FloatingPointModel))
+ << attrTagT(_ForceConformanceInForLoopScope, tool.ForceConformanceInForLoopScope)
+ << attrTagX(_ForcedIncludeFiles, tool.ForcedIncludeFiles, ";")
+ << attrTagX(_ForcedUsingFiles, tool.ForcedUsingFiles, ";")
+ << attrTagT(_FunctionLevelLinking, tool.EnableFunctionLevelLinking)
+ << attrTagT(_GenerateXMLDocumentationFiles, tool.GenerateXMLDocumentationFiles)
+ << attrTagT(_IgnoreStandardIncludePath, tool.IgnoreStandardIncludePath)
+ << attrTagS(_InlineFunctionExpansion, toString(tool.InlineFunctionExpansion))
+ << attrTagT(_IntrinsicFunctions, tool.EnableIntrinsicFunctions)
+ << attrTagT(_MinimalRebuild, tool.MinimalRebuild)
+ << attrTagT(_MultiProcessorCompilation, tool.MultiProcessorCompilation)
+ << attrTagS(_ObjectFileName, tool.ObjectFile)
+//unused << attrTagX(_ObjectFiles, tool.ObjectFiles, ";")
+ << attrTagT(_OmitDefaultLibName, tool.OmitDefaultLibName)
+ << attrTagT(_OmitFramePointers, tool.OmitFramePointers)
+ << attrTagT(_OpenMPSupport, tool.OpenMP)
+ << attrTagS(_Optimization, toString(tool.Optimization))
+ << attrTagS(_PrecompiledHeader, toString(tool.UsePrecompiledHeader))
+ << attrTagS(_PrecompiledHeaderFile, tool.PrecompiledHeaderThrough)
+ << attrTagS(_PrecompiledHeaderOutputFile, tool.PrecompiledHeaderFile)
+ << attrTagT(_PreprocessKeepComments, tool.KeepComments)
+ << attrTagX(_PreprocessorDefinitions, tool.PreprocessorDefinitions, ";")
+ << attrTagS(_PreprocessOutputPath, tool.PreprocessOutputPath)
+ << attrTagT(_PreprocessSuppressLineNumbers, tool.PreprocessSuppressLineNumbers)
+ << attrTagT(_PreprocessToFile, toTriState(tool.GeneratePreprocessedFile))
+ << attrTagS(_ProgramDataBaseFileName, tool.ProgramDataBaseFileName)
+ << attrTagS(_ProcessorNumber, tool.MultiProcessorCompilationProcessorCount)
+ << attrTagS(_RuntimeLibrary, toString(tool.RuntimeLibrary))
+ << attrTagT(_RuntimeTypeInfo, tool.RuntimeTypeInfo)
+ << attrTagT(_ShowIncludes, tool.ShowIncludes)
+ << attrTagT(_SmallerTypeCheck, tool.SmallerTypeCheck)
+ << attrTagT(_StringPooling, tool.StringPooling)
+ << attrTagS(_StructMemberAlignment, toString(tool.StructMemberAlignment))
+ << attrTagT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+//unused << attrTagS(_TreatSpecificWarningsAsErrors, tool.TreatSpecificWarningsAsErrors)
+ << attrTagT(_TreatWarningAsError, tool.WarnAsError)
+ << attrTagT(_TreatWChar_tAsBuiltInType, tool.TreatWChar_tAsBuiltInType)
+ << attrTagT(_UndefineAllPreprocessorDefinitions, tool.UndefineAllPreprocessorDefinitions)
+ << attrTagX(_UndefinePreprocessorDefinitions, tool.UndefinePreprocessorDefinitions, ";")
+ << attrTagT(_UseFullPaths, tool.DisplayFullPaths)
+ << attrTagT(_UseUnicodeForAssemblerListing, tool.UseUnicodeForAssemblerListing)
+ << attrTagS(_WarningLevel, toString(tool.WarningLevel))
+ << attrTagT(_WholeProgramOptimization, tool.WholeProgramOptimization)
+ << attrTagS(_XMLDocumentationFileName, tool.XMLDocumentationFileName)
+ << closetag(_CLCompile);
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, const VCLinkerTool &tool)
+{
+ xml
+ << tag(_Link)
+ << attrTagX(_AdditionalDependencies, tool.AdditionalDependencies, ";")
+ << attrTagX(_AdditionalLibraryDirectories, tool.AdditionalLibraryDirectories, ";")
+ << attrTagX(_AdditionalManifestDependencies, tool.AdditionalManifestDependencies, ";")
+ << attrTagX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrTagX(_AddModuleNamesToAssembly, tool.AddModuleNamesToAssembly, ";")
+ << attrTagT(_AllowIsolation, tool.AllowIsolation)
+ << attrTagT(_AssemblyDebug, tool.AssemblyDebug)
+ << attrTagX(_AssemblyLinkResource, tool.AssemblyLinkResource, ";")
+ << attrTagS(_BaseAddress, tool.BaseAddress)
+ << attrTagS(_CLRImageType, tool.CLRImageType)
+ << attrTagS(_CLRSupportLastError, tool.CLRSupportLastError)
+ << attrTagS(_CLRThreadAttribute, tool.CLRThreadAttribute)
+ << attrTagT(_CLRUnmanagedCodeCheck, tool.CLRUnmanagedCodeCheck)
+//unused << attrTagS(_CreateHotPatchableImage, tool.CreateHotPatchableImage)
+ << attrTagT(_DataExecutionPrevention, tool.DataExecutionPrevention)
+ << attrTagX(_DelayLoadDLLs, tool.DelayLoadDLLs, ";")
+ << attrTagT(_DelaySign, tool.DelaySign)
+ << attrTagS(_EmbedManagedResourceFile, tool.LinkToManagedResourceFile)
+ << attrTagT(_EnableCOMDATFolding, toTriState(tool.EnableCOMDATFolding))
+ << attrTagT(_EnableUAC, tool.EnableUAC)
+ << attrTagS(_EntryPointSymbol, tool.EntryPointSymbol)
+ << attrTagX(_ForceSymbolReferences, tool.ForceSymbolReferences, ";")
+ << attrTagS(_FunctionOrder, tool.FunctionOrder)
+ << attrTagT(_GenerateDebugInformation, tool.GenerateDebugInformation)
+ << attrTagT(_GenerateManifest, tool.GenerateManifest)
+ << attrTagT(_GenerateMapFile, tool.GenerateMapFile)
+ << attrTagL(_HeapCommitSize, tool.HeapCommitSize, /*ifNot*/ -1)
+ << attrTagL(_HeapReserveSize, tool.HeapReserveSize, /*ifNot*/ -1)
+ << attrTagT(_IgnoreAllDefaultLibraries, tool.IgnoreAllDefaultLibraries)
+ << attrTagT(_IgnoreEmbeddedIDL, tool.IgnoreEmbeddedIDL)
+ << attrTagT(_IgnoreImportLibrary, tool.IgnoreImportLibrary)
+ << attrTagX(_IgnoreSpecificDefaultLibraries, tool.IgnoreDefaultLibraryNames, ";")
+ << attrTagS(_ImportLibrary, tool.ImportLibrary)
+ << attrTagS(_KeyContainer, tool.KeyContainer)
+ << attrTagS(_KeyFile, tool.KeyFile)
+ << attrTagT(_LargeAddressAware, toTriState(tool.LargeAddressAware))
+ << attrTagT(_LinkDLL, (tool.config->ConfigurationType == typeDynamicLibrary ? _True : unset))
+ << attrTagS(_LinkErrorReporting, tool.LinkErrorReporting)
+ << attrTagT(_LinkIncremental, toTriState(tool.LinkIncremental))
+ << attrTagT(_LinkStatus, toTriState(tool.ShowProgress))
+ << attrTagS(_LinkTimeCodeGeneration, toString(tool.LinkTimeCodeGeneration))
+ << attrTagS(_ManifestFile, tool.ManifestFile)
+ << attrTagT(_MapExports, tool.MapExports)
+ << attrTagS(_MapFileName, tool.MapFileName)
+ << attrTagS(_MergedIDLBaseFileName, tool.MergedIDLBaseFileName)
+ << attrTagS(_MergeSections, tool.MergeSections)
+ << attrTagS(_MidlCommandFile, tool.MidlCommandFile)
+ << attrTagS(_ModuleDefinitionFile, tool.ModuleDefinitionFile)
+ << attrTagT(_NoEntryPoint, tool.ResourceOnlyDLL)
+ << attrTagT(_OptimizeReferences, toTriState(tool.OptimizeReferences))
+ << attrTagS(_OutputFile, tool.OutputFile)
+ << attrTagT(_PreventDllBinding, tool.PreventDllBinding)
+ << attrTagS(_ProgramDatabaseFile, tool.ProgramDatabaseFile)
+ << attrTagT(_RandomizedBaseAddress, tool.RandomizedBaseAddress)
+ << attrTagT(_RegisterOutput, tool.RegisterOutput)
+ << attrTagL(_SectionAlignment, tool.SectionAlignment, /*ifNot*/ -1)
+ << attrTagT(_SetChecksum, tool.SetChecksum)
+ << attrTagL(_StackCommitSize, tool.StackCommitSize, /*ifNot*/ -1)
+ << attrTagL(_StackReserveSize, tool.StackReserveSize, /*ifNot*/ -1)
+ << attrTagS(_StripPrivateSymbols, tool.StripPrivateSymbols)
+ << attrTagS(_SubSystem, toString(tool.SubSystem))
+// << attrTagT(_SupportNobindOfDelayLoadedDLL, tool.SupportNobindOfDelayLoadedDLL)
+ << attrTagT(_SupportUnloadOfDelayLoadedDLL, tool.SupportUnloadOfDelayLoadedDLL)
+ << attrTagT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+ << attrTagT(_SwapRunFromCD, tool.SwapRunFromCD)
+ << attrTagT(_SwapRunFromNet, tool.SwapRunFromNet)
+ << attrTagS(_TargetMachine, toString(tool.TargetMachine))
+ << attrTagT(_TerminalServerAware, toTriState(tool.TerminalServerAware))
+ << attrTagT(_TreatLinkerWarningAsErrors, tool.TreatWarningsAsErrors)
+ << attrTagT(_TurnOffAssemblyGeneration, tool.TurnOffAssemblyGeneration)
+ << attrTagS(_TypeLibraryFile, tool.TypeLibraryFile)
+ << attrTagL(_TypeLibraryResourceID, tool.TypeLibraryResourceID, /*ifNot*/ 0)
+ << attrTagS(_UACExecutionLevel, tool.UACExecutionLevel)
+ << attrTagT(_UACUIAccess, tool.UACUIAccess)
+ << attrTagS(_Version, tool.Version)
+ << closetag(_Link);
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, const VCMIDLTool &tool)
+{
+ xml
+ << tag(_Midl)
+ << attrTagX(_AdditionalIncludeDirectories, tool.AdditionalIncludeDirectories, ";")
+ << attrTagX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrTagT(_ApplicationConfigurationMode, tool.ApplicationConfigurationMode)
+ << attrTagS(_ClientStubFile, tool.ClientStubFile)
+ << attrTagX(_CPreprocessOptions, tool.CPreprocessOptions, " ")
+ << attrTagS(_DefaultCharType, toString(tool.DefaultCharType))
+ << attrTagS(_DLLDataFileName, tool.DLLDataFileName)
+ << attrTagS(_EnableErrorChecks, toString(tool.EnableErrorChecks))
+ << attrTagT(_ErrorCheckAllocations, tool.ErrorCheckAllocations)
+ << attrTagT(_ErrorCheckBounds, tool.ErrorCheckBounds)
+ << attrTagT(_ErrorCheckEnumRange, tool.ErrorCheckEnumRange)
+ << attrTagT(_ErrorCheckRefPointers, tool.ErrorCheckRefPointers)
+ << attrTagT(_ErrorCheckStubData, tool.ErrorCheckStubData)
+ << attrTagS(_GenerateClientFiles, tool.GenerateClientFiles)
+ << attrTagS(_GenerateServerFiles, tool.GenerateServerFiles)
+ << attrTagT(_GenerateStublessProxies, tool.GenerateStublessProxies)
+ << attrTagT(_GenerateTypeLibrary, tool.GenerateTypeLibrary)
+ << attrTagS(_HeaderFileName, tool.HeaderFileName)
+ << attrTagT(_IgnoreStandardIncludePath, tool.IgnoreStandardIncludePath)
+ << attrTagS(_InterfaceIdentifierFileName, tool.InterfaceIdentifierFileName)
+ << attrTagL(_LocaleID, tool.LocaleID, /*ifNot*/ -1)
+ << attrTagT(_MkTypLibCompatible, tool.MkTypLibCompatible)
+ << attrTagS(_OutputDirectory, tool.OutputDirectory)
+ << attrTagX(_PreprocessorDefinitions, tool.PreprocessorDefinitions, ";")
+ << attrTagS(_ProxyFileName, tool.ProxyFileName)
+ << attrTagS(_RedirectOutputAndErrors, tool.RedirectOutputAndErrors)
+ << attrTagS(_ServerStubFile, tool.ServerStubFile)
+ << attrTagS(_StructMemberAlignment, toString(tool.StructMemberAlignment))
+ << attrTagT(_SuppressCompilerWarnings, tool.SuppressCompilerWarnings)
+ << attrTagT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+ << attrTagS(_TargetEnvironment, toString(tool.TargetEnvironment))
+ << attrTagS(_TypeLibFormat, tool.TypeLibFormat)
+ << attrTagS(_TypeLibraryName, tool.TypeLibraryName)
+ << attrTagX(_UndefinePreprocessorDefinitions, tool.UndefinePreprocessorDefinitions, ";")
+ << attrTagT(_ValidateAllParameters, tool.ValidateAllParameters)
+ << attrTagT(_WarnAsError, tool.WarnAsError)
+ << attrTagS(_WarningLevel, toString(tool.WarningLevel))
+ << closetag(_Midl);
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, const VCCustomBuildTool &tool)
+{
+ const QString &configName = tool.config->Name;
+
+ if ( !tool.AdditionalDependencies.isEmpty() )
+ {
+ xml << tag("AdditionalInputs")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(configName))
+ << valueTagDefX(tool.AdditionalDependencies, "AdditionalInputs", ";");
+ }
+
+ if( !tool.CommandLine.isEmpty() )
+ {
+ xml << tag("Command")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(configName))
+ << valueTag(tool.CommandLine.join(vcxCommandSeparator()));
+ }
+
+ if ( !tool.Description.isEmpty() )
+ {
+ xml << tag("Message")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(configName))
+ << valueTag(tool.Description);
+ }
+
+ if ( !tool.Outputs.isEmpty() )
+ {
+ xml << tag("Outputs")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(configName))
+ << valueTagDefX(tool.Outputs, "Outputs", ";");
+ }
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, const VCLibrarianTool &tool)
+{
+ xml
+ << tag(_Link)
+ << attrTagX(_AdditionalDependencies, tool.AdditionalDependencies, ";")
+ << attrTagX(_AdditionalLibraryDirectories, tool.AdditionalLibraryDirectories, ";")
+ << attrTagX(_AdditionalOptions, tool.AdditionalOptions, " ")
+//unused << attrTagS(_DisplayLibrary, tool.DisplayLibrary)
+//unused << attrTagS(_ErrorReporting, tool.ErrorReporting)
+ << attrTagX(_ExportNamedFunctions, tool.ExportNamedFunctions, ";")
+ << attrTagX(_ForceSymbolReferences, tool.ForceSymbolReferences, ";")
+ << attrTagT(_IgnoreAllDefaultLibraries, tool.IgnoreAllDefaultLibraries)
+ << attrTagX(_IgnoreSpecificDefaultLibraries, tool.IgnoreDefaultLibraryNames, ";")
+//unused << attrTagT(_LinkTimeCodeGeneration, tool.LinkTimeCodeGeneration)
+ << attrTagS(_ModuleDefinitionFile, tool.ModuleDefinitionFile)
+//unused << attrTagS(_Name, tool.Name)
+ << attrTagS(_OutputFile, tool.OutputFile)
+//unused << attrTagX(_RemoveObjects, tool.RemoveObjects, ";")
+//unused << attrTagS(_SubSystem, tool.SubSystem)
+ << attrTagT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+//unused << attrTagS(_TargetMachine, tool.TargetMachine)
+//unused << attrTagT(_TreatLibWarningAsErrors, tool.TreatLibWarningAsErrors)
+//unused << attrTagT(_Verbose, tool.Verbose)
+ << closetag(_Link);
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, const VCResourceCompilerTool &tool)
+{
+ xml
+ << tag(_ResourceCompile)
+ << attrTagX(_AdditionalIncludeDirectories, tool.AdditionalIncludeDirectories, ";")
+ << attrTagX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrTagS(_Culture, toString(tool.Culture))
+ << attrTagT(_IgnoreStandardIncludePath, tool.IgnoreStandardIncludePath)
+//unused << attrTagT(_NullTerminateStrings, tool.NullTerminateStrings)
+ << attrTagX(_PreprocessorDefinitions, tool.PreprocessorDefinitions, ";")
+ << attrTagS(_ResourceOutputFileName, tool.ResourceOutputFileName)
+ << attrTagT(_ShowProgress, toTriState(tool.ShowProgress))
+ << attrTagT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+//unused << attrTagS(_TrackerLogDirectory, tool.TrackerLogDirectory)
+//unused << attrTagS(_UndefinePreprocessorDefinitions, tool.UndefinePreprocessorDefinitions)
+ << closetag(_ResourceCompile);
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, const VCEventTool &tool)
+{
+ xml
+ << tag(tool.EventName)
+ << attrTagS(_Command, tool.CommandLine.join(vcxCommandSeparator()))
+ << attrTagS(_Message, tool.Description)
+ << closetag(tool.EventName);
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, const VCDeploymentTool &tool)
+{
+ Q_UNUSED(xml);
+ Q_UNUSED(tool);
+ // SmartDevice deployment not supported in VS 2010
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, const VCConfiguration &tool)
+{
+ xml << tag("PropertyGroup")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(tool.Name))
+ << attrTag("Label", "Configuration")
+ << attrTagS(_OutputDirectory, tool.OutputDirectory)
+ << attrTagT(_ATLMinimizesCRunTimeLibraryUsage, tool.ATLMinimizesCRunTimeLibraryUsage)
+ << attrTagT(_BuildBrowserInformation, tool.BuildBrowserInformation)
+ << attrTagS(_CharacterSet, toString(tool.CharacterSet))
+ << attrTagS(_ConfigurationType, toString(tool.ConfigurationType))
+ << attrTagS(_DeleteExtensionsOnClean, tool.DeleteExtensionsOnClean)
+ << attrTagS(_ImportLibrary, tool.ImportLibrary)
+ << attrTagS(_IntermediateDirectory, tool.IntermediateDirectory)
+ << attrTagS(_PrimaryOutput, tool.PrimaryOutput)
+ << attrTagS(_ProgramDatabase, tool.ProgramDatabase)
+ << attrTagT(_RegisterOutput, tool.RegisterOutput)
+ << attrTagS(_UseOfATL, toString(tool.UseOfATL))
+ << attrTagS(_UseOfMfc, toString(tool.UseOfMfc))
+ << attrTagT(_WholeProgramOptimization, tool.WholeProgramOptimization)
+ << closetag();
+}
+
+void VCXProjectWriter::write(XmlOutput &xml, VCFilter &tool)
+{
+ Q_UNUSED(xml);
+ Q_UNUSED(tool);
+ // unused in this generator
+}
+
+void VCXProjectWriter::addFilters(VCProject &project, XmlOutput &xmlFilter, const QString &filtername)
+{
+ bool added = false;
+
+ for (int i = 0; i < project.SingleProjects.count(); ++i) {
+ VCFilter filter;
+ const VCProjectSingleConfig &singleCfg = project.SingleProjects.at(i);
+ if (filtername == "Root Files") {
+ filter = singleCfg.RootFiles;
+ } else if (filtername == "Source Files") {
+ filter = singleCfg.SourceFiles;
+ } else if (filtername == "Header Files") {
+ filter = singleCfg.HeaderFiles;
+ } else if (filtername == "Generated Files") {
+ filter = singleCfg.GeneratedFiles;
+ } else if (filtername == "LexYacc Files") {
+ filter = singleCfg.LexYaccFiles;
+ } else if (filtername == "Translation Files") {
+ filter = singleCfg.TranslationFiles;
+ } else if (filtername == "Form Files") {
+ filter = singleCfg.FormFiles;
+ } else if (filtername == "Resource Files") {
+ filter = singleCfg.ResourceFiles;
+ } else {
+ // ExtraCompilers
+ filter = project.SingleProjects[i].filterForExtraCompiler(filtername);
+ }
+
+ if(!filter.Files.isEmpty() && !added) {
+ xmlFilter << tag("Filter")
+ << attrTag("Include", filtername)
+ << attrTagS("UniqueIdentifier", filter.Guid)
+ << attrTagS("Extensions", filter.Filter)
+ << attrTagT("ParseFiles", filter.ParseFiles)
+ << closetag();
+ }
+ }
+}
+
+// outputs a given filter for all existing configurations of a project
+void VCXProjectWriter::outputFilter(VCProject &project, XmlOutput &xml, XmlOutput &xmlFilter, const QString &filtername)
+{
+ XNode *root;
+ if (project.SingleProjects.at(0).flat_files)
+ root = new XFlatNode;
+ else
+ root = new XTreeNode;
+
+ QString name, extfilter;
+ triState parse;
+
+ for (int i = 0; i < project.SingleProjects.count(); ++i) {
+ VCFilter filter;
+ const VCProjectSingleConfig &singleCfg = project.SingleProjects.at(i);
+ if (filtername == "Root Files") {
+ filter = singleCfg.RootFiles;
+ } else if (filtername == "Source Files") {
+ filter = singleCfg.SourceFiles;
+ } else if (filtername == "Header Files") {
+ filter = singleCfg.HeaderFiles;
+ } else if (filtername == "Generated Files") {
+ filter = singleCfg.GeneratedFiles;
+ } else if (filtername == "LexYacc Files") {
+ filter = singleCfg.LexYaccFiles;
+ } else if (filtername == "Translation Files") {
+ filter = singleCfg.TranslationFiles;
+ } else if (filtername == "Form Files") {
+ filter = singleCfg.FormFiles;
+ } else if (filtername == "Resource Files") {
+ filter = singleCfg.ResourceFiles;
+ } else {
+ // ExtraCompilers
+ filter = project.SingleProjects[i].filterForExtraCompiler(filtername);
+ }
+
+ // Merge all files in this filter to root tree
+ for (int x = 0; x < filter.Files.count(); ++x)
+ root->addElement(filter.Files.at(x));
+
+ // Save filter setting from first filter. Next filters
+ // may differ but we cannot handle that. (ex. extfilter)
+ if (name.isEmpty()) {
+ name = filter.Name;
+ extfilter = filter.Filter;
+ parse = filter.ParseFiles;
+ }
+ }
+
+ if (!root->hasElements())
+ return;
+
+ root->generateXML(xml, xmlFilter, "", project, filtername); // output root tree
+}
+
+// Output all configurations (by filtername) for a file (by info)
+// A filters config output is in VCFilter.outputFileConfig()
+void VCXProjectWriter::outputFileConfigs(VCProject &project, XmlOutput &xml, XmlOutput &xmlFilter, const VCFilterFile &info, const QString &filtername)
+{
+ // We need to check if the file has any custom build step.
+ // If there is one then it has to be included with "CustomBuild Include"
+ bool fileAdded = false;
+
+ for (int i = 0; i < project.SingleProjects.count(); ++i) {
+ VCFilter filter;
+ const VCProjectSingleConfig &singleCfg = project.SingleProjects.at(i);
+ if (filtername.startsWith("Root Files")) {
+ filter = singleCfg.RootFiles;
+ } else if (filtername.startsWith("Source Files")) {
+ filter = singleCfg.SourceFiles;
+ } else if (filtername.startsWith("Header Files")) {
+ filter = singleCfg.HeaderFiles;
+ } else if (filtername.startsWith("Generated Files")) {
+ filter = singleCfg.GeneratedFiles;
+ } else if (filtername.startsWith("LexYacc Files")) {
+ filter = singleCfg.LexYaccFiles;
+ } else if (filtername.startsWith("Translation Files")) {
+ filter = singleCfg.TranslationFiles;
+ } else if (filtername.startsWith("Form Files")) {
+ filter = singleCfg.FormFiles;
+ } else if (filtername.startsWith("Resource Files")) {
+ filter = singleCfg.ResourceFiles;
+ } else {
+ // ExtraCompilers
+ filter = project.SingleProjects[i].filterForExtraCompiler(filtername);
+ }
+
+ if (filter.Config) // only if the filter is not empty
+ if (outputFileConfig(filter, xml, xmlFilter, info.file, filtername, fileAdded)) // only add it once.
+ fileAdded = true;
+ }
+
+ if ( !fileAdded )
+ {
+ if (filtername.startsWith("Source Files")) {
+
+ xmlFilter << tag("ClCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("ClCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file));
+
+ } else if(filtername.startsWith("Header Files")) {
+
+ xmlFilter << tag("ClInclude")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("ClInclude")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file));
+ } else if(filtername.startsWith("Generated Files") || filtername.startsWith("Form Files")) {
+
+ if (info.file.endsWith(".h")) {
+
+ xmlFilter << tag("ClInclude")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("ClInclude")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file));
+ } else if(info.file.endsWith(".cpp")) {
+
+ xmlFilter << tag("ClCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("ClCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file));
+ } else if(info.file.endsWith(".res")) {
+
+ xmlFilter << tag("CustomBuild")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("CustomBuild")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file));
+ } else {
+
+ xmlFilter << tag("CustomBuild")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("CustomBuild")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file));
+ }
+
+ } else if(filtername.startsWith("Root Files")) {
+
+ if (info.file.endsWith(".rc")) {
+
+ xmlFilter << tag("ResourceCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file));
+
+ xml << tag("ResourceCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file));
+ }
+ } else {
+
+ xmlFilter << tag("None")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("None")
+ << attrTag("Include",Option::fixPathToLocalOS(info.file));
+ }
+ }
+
+ xml << closetag();
+ xmlFilter << closetag();
+}
+
+bool VCXProjectWriter::outputFileConfig(VCFilter &filter, XmlOutput &xml, XmlOutput &xmlFilter, const QString &filename, const QString &filtername, bool fileAllreadyAdded)
+{
+ bool fileAdded = false;
+
+ // Clearing each filter tool
+ filter.useCustomBuildTool = false;
+ filter.useCompilerTool = false;
+ filter.CustomBuildTool = VCCustomBuildTool();
+ filter.CompilerTool = VCCLCompilerTool();
+
+ // Unset some default options
+ filter.CustomBuildTool.config = filter.Config;
+ filter.CompilerTool.BufferSecurityCheck = unset;
+ filter.CompilerTool.DebugInformationFormat = debugUnknown;
+ filter.CompilerTool.ExceptionHandling = ehDefault;
+ filter.CompilerTool.ProgramDataBaseFileName.clear();
+ filter.CompilerTool.RuntimeLibrary = rtUnknown;
+ filter.CompilerTool.config = filter.Config;
+
+ bool inBuild = false;
+ VCFilterFile info;
+ for (int i = 0; i < filter.Files.count(); ++i) {
+ if (filter.Files.at(i).file == filename) {
+ info = filter.Files.at(i);
+ inBuild = true;
+ }
+ }
+ inBuild &= !info.excludeFromBuild;
+
+ if (inBuild) {
+ filter.addExtraCompiler(info);
+ if (filter.Project->usePCH)
+ filter.modifyPCHstage(info.file);
+ } else {
+ // Excluded files uses an empty compiler stage
+ if(info.excludeFromBuild)
+ filter.useCompilerTool = true;
+ }
+
+ // Actual XML output ----------------------------------
+ if (filter.useCustomBuildTool || filter.useCompilerTool || !inBuild) {
+
+ if (filter.useCustomBuildTool)
+ {
+ if ( !fileAllreadyAdded ) {
+
+ fileAdded = true;
+
+ xmlFilter << tag("CustomBuild")
+ << attrTag("Include",Option::fixPathToLocalOS(filename))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("CustomBuild")
+ << attrTag("Include",Option::fixPathToLocalOS(filename));
+
+ if ( filtername.startsWith("Form Files") || filtername.startsWith("Generated Files") || filtername.startsWith("Resource Files") )
+ xml << attrTagS("FileType", "Document");
+ }
+
+ filter.Project->projectWriter->write(xml, filter.CustomBuildTool);
+ }
+
+ if ( !fileAdded && !fileAllreadyAdded )
+ {
+ fileAdded = true;
+
+ if (filtername.startsWith("Source Files")) {
+
+ xmlFilter << tag("ClCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(filename))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("ClCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(filename));
+
+ } else if(filtername.startsWith("Header Files")) {
+
+ xmlFilter << tag("ClInclude")
+ << attrTag("Include",Option::fixPathToLocalOS(filename))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("ClInclude")
+ << attrTag("Include",Option::fixPathToLocalOS(filename));
+ } else if(filtername.startsWith("Generated Files") || filtername.startsWith("Form Files")) {
+
+ if (filename.endsWith(".h")) {
+
+ xmlFilter << tag("ClInclude")
+ << attrTag("Include",Option::fixPathToLocalOS(filename))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("ClInclude")
+ << attrTag("Include",Option::fixPathToLocalOS(filename));
+ } else if(filename.endsWith(".cpp")) {
+
+ xmlFilter << tag("ClCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(filename))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("ClCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(filename));
+ } else if(filename.endsWith(".res")) {
+
+ xmlFilter << tag("CustomBuild")
+ << attrTag("Include",Option::fixPathToLocalOS(filename))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("CustomBuild")
+ << attrTag("Include",Option::fixPathToLocalOS(filename));
+ } else {
+
+ xmlFilter << tag("CustomBuild")
+ << attrTag("Include",Option::fixPathToLocalOS(filename))
+ << attrTagS("Filter", filtername);
+
+ xml << tag("CustomBuild")
+ << attrTag("Include",Option::fixPathToLocalOS(filename));
+ }
+ } else if(filtername.startsWith("Root Files")) {
+
+ if (filename.endsWith(".rc")) {
+
+ xmlFilter << tag("ResourceCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(filename));
+
+ xml << tag("ResourceCompile")
+ << attrTag("Include",Option::fixPathToLocalOS(filename));
+ }
+ }
+ }
+
+ if(!inBuild) {
+
+ xml << tag("ExcludedFromBuild")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(filter.Config->Name))
+ << valueTag("true");
+ }
+
+ if (filter.useCompilerTool) {
+
+ if ( !filter.CompilerTool.ForcedIncludeFiles.isEmpty() ) {
+ xml << tag("ForcedIncludeFiles")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(filter.Config->Name))
+ << valueTagX(filter.CompilerTool.ForcedIncludeFiles);
+ }
+
+ if ( !filter.CompilerTool.PrecompiledHeaderThrough.isEmpty() ) {
+
+ xml << tag("PrecompiledHeaderFile")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(filter.Config->Name))
+ << valueTag(filter.CompilerTool.PrecompiledHeaderThrough)
+ << tag("PrecompiledHeader")
+ << attrTag("Condition", QString("'$(Configuration)|$(Platform)'=='%1'").arg(filter.Config->Name))
+ << valueTag(toString(filter.CompilerTool.UsePrecompiledHeader));
+ }
+ }
+ }
+
+ return fileAdded;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/msbuild_objectmodel.h b/qmake/generators/win32/msbuild_objectmodel.h
new file mode 100644
index 0000000000..c80a2708fa
--- /dev/null
+++ b/qmake/generators/win32/msbuild_objectmodel.h
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** 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 MSBUILD_OBJECTMODEL_H
+#define MSBUILD_OBJECTMODEL_H
+
+#include "project.h"
+#include "xmloutput.h"
+#include "msvc_objectmodel.h"
+#include <qatomic.h>
+#include <qlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qmap.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+// Tree & Flat view of files --------------------------------------------------
+class XNode
+{
+public:
+ virtual ~XNode() { }
+ void addElement(const VCFilterFile &file) {
+ addElement(file.file, file);
+ }
+ virtual void addElement(const QString &filepath, const VCFilterFile &allInfo) = 0;
+ virtual void removeElements()= 0;
+ virtual void generateXML(XmlOutput &xml, XmlOutput &xmlFilter, const QString &tagName, VCProject &tool, const QString &filter) = 0;
+ virtual bool hasElements() = 0;
+};
+
+class XTreeNode : public XNode
+{
+ typedef QMap<QString, XTreeNode*> ChildrenMap;
+ VCFilterFile info;
+ ChildrenMap children;
+
+public:
+ virtual ~XTreeNode() { removeElements(); }
+
+ int pathIndex(const QString &filepath) {
+ int Windex = filepath.indexOf("\\");
+ int Uindex = filepath.indexOf("/");
+ if (Windex != -1 && Uindex != -1)
+ return qMin(Windex, Uindex);
+ else if (Windex != -1)
+ return Windex;
+ return Uindex;
+ }
+
+ void addElement(const QString &filepath, const VCFilterFile &allInfo){
+ QString newNodeName(filepath);
+
+ int index = pathIndex(filepath);
+ if (index != -1)
+ newNodeName = filepath.left(index);
+
+ XTreeNode *n = children.value(newNodeName);
+ if (!n) {
+ n = new XTreeNode;
+ n->info = allInfo;
+ children.insert(newNodeName, n);
+ }
+ if (index != -1)
+ n->addElement(filepath.mid(index+1), allInfo);
+ }
+
+ void removeElements() {
+ ChildrenMap::ConstIterator it = children.constBegin();
+ ChildrenMap::ConstIterator end = children.constEnd();
+ for( ; it != end; it++) {
+ (*it)->removeElements();
+ delete it.value();
+ }
+ children.clear();
+ }
+
+ void generateXML(XmlOutput &xml, XmlOutput &xmlFilter, const QString &tagName, VCProject &tool, const QString &filter);
+ bool hasElements() {
+ return children.size() != 0;
+ }
+};
+
+class XFlatNode : public XNode
+{
+ typedef QMap<QString, VCFilterFile> ChildrenMapFlat;
+ ChildrenMapFlat children;
+
+public:
+ virtual ~XFlatNode() { removeElements(); }
+
+ int pathIndex(const QString &filepath) {
+ int Windex = filepath.lastIndexOf("\\");
+ int Uindex = filepath.lastIndexOf("/");
+ if (Windex != -1 && Uindex != -1)
+ return qMax(Windex, Uindex);
+ else if (Windex != -1)
+ return Windex;
+ return Uindex;
+ }
+
+ void addElement(const QString &filepath, const VCFilterFile &allInfo){
+ QString newKey(filepath);
+
+ int index = pathIndex(filepath);
+ if (index != -1)
+ newKey = filepath.mid(index+1);
+
+ // Key designed to sort files with same
+ // name in different paths correctly
+ children.insert(newKey + "\0" + allInfo.file, allInfo);
+ }
+
+ void removeElements() {
+ children.clear();
+ }
+
+ void generateXML(XmlOutput &xml, XmlOutput &xmlFilter, const QString &tagName, VCProject &proj, const QString &filter);
+ bool hasElements() {
+ return children.size() != 0;
+ }
+};
+
+class VCXProjectWriter : public VCProjectWriter
+{
+public:
+ void write(XmlOutput &, VCProjectSingleConfig &);
+ void write(XmlOutput &, VCProject &);
+
+ void write(XmlOutput &, const VCCLCompilerTool &);
+ void write(XmlOutput &, const VCLinkerTool &);
+ void write(XmlOutput &, const VCMIDLTool &);
+ void write(XmlOutput &, const VCCustomBuildTool &);
+ void write(XmlOutput &, const VCLibrarianTool &);
+ void write(XmlOutput &, const VCResourceCompilerTool &);
+ void write(XmlOutput &, const VCEventTool &);
+ void write(XmlOutput &, const VCDeploymentTool &);
+ void write(XmlOutput &, const VCConfiguration &);
+ void write(XmlOutput &, VCFilter &);
+
+private:
+ static void addFilters(VCProject &project, XmlOutput &xmlFilter, const QString &filterName);
+ static void outputFilter(VCProject &project, XmlOutput &xml, XmlOutput &xmlFilter, const QString &filtername);
+ static void outputFileConfigs(VCProject &project, XmlOutput &xml, XmlOutput &xmlFilter, const VCFilterFile &info, const QString &filtername);
+ static bool outputFileConfig(VCFilter &filter, XmlOutput &xml, XmlOutput &xmlFilter, const QString &filename, const QString &filtername, bool fileAllreadyAdded);
+
+ friend class XTreeNode;
+ friend class XFlatNode;
+};
+
+QT_END_NAMESPACE
+
+#endif // MSVC_OBJECTMODEL_H
diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp
new file mode 100644
index 0000000000..c55806d002
--- /dev/null
+++ b/qmake/generators/win32/msvc_nmake.cpp
@@ -0,0 +1,361 @@
+/****************************************************************************
+**
+** 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 "msvc_nmake.h"
+#include "option.h"
+#include <qregexp.h>
+#include <qhash.h>
+#include <qdir.h>
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+NmakeMakefileGenerator::NmakeMakefileGenerator() : Win32MakefileGenerator(), init_flag(false)
+{
+
+}
+
+bool
+NmakeMakefileGenerator::writeMakefile(QTextStream &t)
+{
+ writeHeader(t);
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
+ t << *it << " ";
+ t << "all first clean:" << "\n\t"
+ << "@echo \"Some of the required modules ("
+ << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
+ << "@echo \"Skipped.\"" << endl << endl;
+ writeMakeQmake(t);
+ return true;
+ }
+
+ if(project->first("TEMPLATE") == "app" ||
+ project->first("TEMPLATE") == "lib") {
+#if 0
+ if(Option::mkfile::do_stub_makefile)
+ return MakefileGenerator::writeStubMakefile(t);
+#endif
+ writeNmakeParts(t);
+ return MakefileGenerator::writeMakefile(t);
+ }
+ else if(project->first("TEMPLATE") == "subdirs") {
+ writeSubDirs(t);
+ return true;
+ }
+ return false;
+}
+
+QString NmakeMakefileGenerator::getPdbTarget()
+{
+ return QString(project->first("TARGET") + project->first("TARGET_VERSION_EXT") + ".pdb");
+}
+
+QString NmakeMakefileGenerator::defaultInstall(const QString &t)
+{
+ if((t != "target" && t != "dlltarget") ||
+ (t == "dlltarget" && (project->first("TEMPLATE") != "lib" || !project->isActiveConfig("shared"))) ||
+ project->first("TEMPLATE") == "subdirs")
+ return QString();
+
+ QString ret = Win32MakefileGenerator::defaultInstall(t);
+
+ const QString root = "$(INSTALL_ROOT)";
+ QStringList &uninst = project->values(t + ".uninstall");
+ QString targetdir = Option::fixPathToTargetOS(project->first(t + ".path"), false);
+ targetdir = fileFixify(targetdir, FileFixifyAbsolute);
+ if(targetdir.right(1) != Option::dir_sep)
+ targetdir += Option::dir_sep;
+
+ if(t == "target" && project->first("TEMPLATE") == "lib") {
+ if(project->isActiveConfig("shared") && project->isActiveConfig("debug")) {
+ QString pdb_target = getPdbTarget();
+ pdb_target.remove('"');
+ QString src_targ = (project->isEmpty("DESTDIR") ? QString("$(DESTDIR)") : project->first("DESTDIR")) + pdb_target;
+ QString dst_targ = filePrefixRoot(root, fileFixify(targetdir + pdb_target, FileFixifyAbsolute));
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += QString("-$(INSTALL_FILE)") + " \"" + src_targ + "\" \"" + dst_targ + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_targ + "\"");
+ }
+ }
+
+ return ret;
+}
+
+QStringList &NmakeMakefileGenerator::findDependencies(const QString &file)
+{
+ QStringList &aList = MakefileGenerator::findDependencies(file);
+ // Note: The QMAKE_IMAGE_COLLECTION file have all images
+ // as dependency, so don't add precompiled header then
+ if (file == project->first("QMAKE_IMAGE_COLLECTION"))
+ return aList;
+ for(QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
+ if(file.endsWith(*it)) {
+ if(!precompObj.isEmpty() && !aList.contains(precompObj))
+ aList += precompObj;
+ break;
+ }
+ }
+ return aList;
+}
+
+void NmakeMakefileGenerator::writeNmakeParts(QTextStream &t)
+{
+ writeStandardParts(t);
+
+ // precompiled header
+ if(usePCH) {
+ QString precompRule = QString("-c -Yc -Fp%1 -Fo%2").arg(precompPch).arg(precompObj);
+ t << precompObj << ": " << precompH << " " << findDependencies(precompH).join(" \\\n\t\t")
+ << "\n\t" << "$(CXX) " + precompRule +" $(CXXFLAGS) $(INCPATH) -TP " << precompH << endl << endl;
+ }
+}
+
+QString NmakeMakefileGenerator::var(const QString &value)
+{
+ if (usePCH) {
+ if ((value == "QMAKE_RUN_CXX_IMP_BATCH"
+ || value == "QMAKE_RUN_CXX_IMP"
+ || value == "QMAKE_RUN_CXX")) {
+ QFileInfo precompHInfo(fileInfo(precompH));
+ QString precompRule = QString("-c -FI%1 -Yu%2 -Fp%3")
+ .arg(precompHInfo.fileName())
+ .arg(precompHInfo.fileName())
+ .arg(precompPch);
+ QString p = MakefileGenerator::var(value);
+ p.replace("-c", precompRule);
+ // Cannot use -Gm with -FI & -Yu, as this gives an
+ // internal compiler error, on the newer compilers
+ // ### work-around for a VS 2003 bug. Move to some prf file or remove completely.
+ p.remove("-Gm");
+ return p;
+ } else if (value == "QMAKE_CXXFLAGS") {
+ // Remove internal compiler error option
+ // ### work-around for a VS 2003 bug. Move to some prf file or remove completely.
+ return MakefileGenerator::var(value).remove("-Gm");
+ }
+ }
+
+ // Normal val
+ return MakefileGenerator::var(value);
+}
+
+void NmakeMakefileGenerator::init()
+{
+ if(init_flag)
+ return;
+ init_flag = true;
+
+ /* 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->values("MAKEFILE").isEmpty())
+ project->values("MAKEFILE").append("Makefile");
+ if(project->isEmpty("QMAKE_COPY_FILE"))
+ project->values("QMAKE_COPY_FILE").append("$(COPY)");
+ if(project->isEmpty("QMAKE_COPY_DIR"))
+ project->values("QMAKE_COPY_DIR").append("xcopy /s /q /y /i");
+ if(project->isEmpty("QMAKE_INSTALL_FILE"))
+ project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
+ project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_DIR"))
+ project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
+ return;
+ }
+
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
+ project->values("QMAKE_LIBS_PRIVATE") += escapeFilePaths(project->values("LIBS_PRIVATE"));
+ processVars();
+
+ if (!project->values("RES_FILE").isEmpty()) {
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("RES_FILE"));
+ }
+
+ if (!project->values("DEF_FILE").isEmpty()) {
+ QString defFileName = fileFixify(project->values("DEF_FILE")).first();
+ project->values("QMAKE_LFLAGS").append(QString("/DEF:") + escapeFilePath(defFileName));
+ }
+
+ if(!project->values("VERSION").isEmpty()) {
+ QString version = project->values("VERSION")[0];
+ int firstDot = version.indexOf(".");
+ QString major = version.left(firstDot);
+ QString minor = version.right(version.length() - firstDot - 1);
+ minor.replace(".", "");
+ project->values("QMAKE_LFLAGS").append("/VERSION:" + major + "." + minor);
+ }
+
+ // Base class init!
+ MakefileGenerator::init();
+
+ // Setup PCH variables
+ precompH = project->first("PRECOMPILED_HEADER");
+ usePCH = !precompH.isEmpty() && project->isActiveConfig("precompile_header");
+ if (usePCH) {
+ // Created files
+ precompObj = var("PRECOMPILED_DIR") + project->first("TARGET") + "_pch" + Option::obj_ext;
+ precompPch = var("PRECOMPILED_DIR") + project->first("TARGET") + "_pch.pch";
+ // Add linking of precompObj (required for whole precompiled classes)
+ project->values("OBJECTS") += precompObj;
+ // Add pch file to cleanup
+ project->values("QMAKE_CLEAN") += precompPch;
+ // Return to variable pool
+ project->values("PRECOMPILED_OBJECT") = QStringList(precompObj);
+ project->values("PRECOMPILED_PCH") = QStringList(precompPch);
+ }
+
+ QString version = project->first("TARGET_VERSION_EXT");
+ if(project->isActiveConfig("shared")) {
+ project->values("QMAKE_CLEAN").append(project->first("DESTDIR") + project->first("TARGET") + version + ".exp");
+ }
+ if(project->isActiveConfig("debug")) {
+ project->values("QMAKE_DISTCLEAN").append(project->first("DESTDIR") + project->first("TARGET") + version + ".pdb");
+ project->values("QMAKE_CLEAN").append(project->first("DESTDIR") + project->first("TARGET") + version + ".ilk");
+ project->values("QMAKE_CLEAN").append("vc*.pdb");
+ project->values("QMAKE_CLEAN").append("vc*.idb");
+ }
+}
+
+void NmakeMakefileGenerator::writeLibDirPart(QTextStream &t)
+{
+ QStringList libDirs = project->values("QMAKE_LIBDIR");
+ for (int i = 0; i < libDirs.size(); ++i)
+ libDirs[i].remove("\"");
+ t << valGlue(libDirs,"/LIBPATH:\"","\" /LIBPATH:\"","\"") << " ";
+}
+
+void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t)
+{
+ t << ".SUFFIXES:";
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << " " << (*cit);
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << " " << (*cppit);
+ t << endl << endl;
+
+ if(!project->isActiveConfig("no_batch")) {
+ // Batchmode doesn't use the non implicit rules QMAKE_RUN_CXX & QMAKE_RUN_CC
+ project->variables().remove("QMAKE_RUN_CXX");
+ project->variables().remove("QMAKE_RUN_CC");
+
+ QHash<QString, void*> source_directories;
+ source_directories.insert(".", (void*)1);
+ QString directories[] = { QString("UI_SOURCES_DIR"), QString("UI_DIR"), QString() };
+ for(int y = 0; !directories[y].isNull(); y++) {
+ QString dirTemp = project->first(directories[y]);
+ if (dirTemp.endsWith("\\"))
+ dirTemp.truncate(dirTemp.length()-1);
+ if(!dirTemp.isEmpty())
+ source_directories.insert(dirTemp, (void*)1);
+ }
+ QString srcs[] = { QString("SOURCES"), QString("GENERATED_SOURCES"), QString() };
+ for(int x = 0; !srcs[x].isNull(); x++) {
+ QStringList &l = project->values(srcs[x]);
+ for(QStringList::Iterator sit = l.begin(); sit != l.end(); ++sit) {
+ QString sep = "\\";
+ if((*sit).indexOf(sep) == -1)
+ sep = "/";
+ QString dir = (*sit).section(sep, 0, -2);
+ if(!dir.isEmpty() && !source_directories[dir])
+ source_directories.insert(dir, (void*)1);
+ }
+ }
+
+ for(QHash<QString, void*>::Iterator it(source_directories.begin()); it != source_directories.end(); ++it) {
+ if(it.key().isEmpty())
+ continue;
+ QString objDir = var("OBJECTS_DIR");
+ if (objDir == ".\\")
+ objDir = "";
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << "{" << it.key() << "}" << (*cppit) << "{" << objDir << "}" << Option::obj_ext << "::\n\t"
+ << var("QMAKE_RUN_CXX_IMP_BATCH").replace(QRegExp("\\$@"), var("OBJECTS_DIR")) << endl << "\t$<" << endl << "<<" << endl << endl;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << "{" << it.key() << "}" << (*cit) << "{" << objDir << "}" << Option::obj_ext << "::\n\t"
+ << var("QMAKE_RUN_CC_IMP_BATCH").replace(QRegExp("\\$@"), var("OBJECTS_DIR")) << endl << "\t$<" << endl << "<<" << endl << endl;
+ }
+ } else {
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << (*cppit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CXX_IMP") << endl << endl;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << (*cit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CC_IMP") << endl << endl;
+ }
+
+}
+
+void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
+{
+ t << "first: all" << endl;
+ t << "all: " << fileFixify(Option::output.fileName()) << " " << varGlue("ALL_DEPS"," "," "," ") << "$(DESTDIR_TARGET)" << endl << endl;
+ t << "$(DESTDIR_TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) " << var("POST_TARGETDEPS");
+
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << "\n\t" <<var("QMAKE_PRE_LINK");
+ if(project->isActiveConfig("staticlib")) {
+ t << "\n\t" << "$(LIBAPP) $(LIBFLAGS) /OUT:$(DESTDIR_TARGET) @<<" << "\n\t "
+ << "$(OBJECTS)";
+ } else {
+ t << "\n\t" << "$(LINK) $(LFLAGS) /OUT:$(DESTDIR_TARGET) @<< " << "\n\t "
+ << "$(OBJECTS) $(LIBS)";
+ }
+ t << endl << "<<";
+ QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE");
+ bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") &&
+ !project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH");
+ if(useSignature) {
+ t << "\n\tsigntool sign /F " << signature << " $(DESTDIR_TARGET)";
+ }
+ if(!project->isEmpty("QMAKE_POST_LINK")) {
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ }
+ t << endl;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/msvc_nmake.h b/qmake/generators/win32/msvc_nmake.h
new file mode 100644
index 0000000000..8954655672
--- /dev/null
+++ b/qmake/generators/win32/msvc_nmake.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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 MSVC_NMAKE_H
+#define MSVC_NMAKE_H
+
+#include "winmakefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class NmakeMakefileGenerator : public Win32MakefileGenerator
+{
+ bool init_flag;
+ void writeNmakeParts(QTextStream &);
+ void writeLibDirPart(QTextStream &t);
+ bool writeMakefile(QTextStream &);
+ void writeImplicitRulesPart(QTextStream &t);
+ void writeBuildRulesPart(QTextStream &t);
+ void init();
+
+protected:
+ virtual QString getPdbTarget();
+ virtual QString defaultInstall(const QString &t);
+ virtual QStringList &findDependencies(const QString &file);
+ QString var(const QString &value);
+ QString precompH, precompObj, precompPch;
+ bool usePCH;
+
+public:
+ NmakeMakefileGenerator();
+ ~NmakeMakefileGenerator();
+
+};
+
+inline NmakeMakefileGenerator::~NmakeMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // MSVC_NMAKE_H
diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp
new file mode 100644
index 0000000000..88a5043519
--- /dev/null
+++ b/qmake/generators/win32/msvc_objectmodel.cpp
@@ -0,0 +1,2909 @@
+/****************************************************************************
+**
+** 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 "msvc_objectmodel.h"
+#include "msvc_vcproj.h"
+#include "msvc_vcxproj.h"
+#include <qstringlist.h>
+#include <qfileinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+// XML Tags ---------------------------------------------------------
+const char _Configuration[] = "Configuration";
+const char _Configurations[] = "Configurations";
+const char q_File[] = "File";
+const char _FileConfiguration[] = "FileConfiguration";
+const char q_Files[] = "Files";
+const char _Filter[] = "Filter";
+const char _Globals[] = "Globals";
+const char _Platform[] = "Platform";
+const char _Platforms[] = "Platforms";
+const char _Tool[] = "Tool";
+const char _VisualStudioProject[] = "VisualStudioProject";
+
+// XML Properties ---------------------------------------------------
+const char _AddModuleNamesToAssembly[] = "AddModuleNamesToAssembly";
+const char _AdditionalDependencies[] = "AdditionalDependencies";
+const char _AdditionalFiles[] = "AdditionalFiles";
+const char _AdditionalIncludeDirectories[] = "AdditionalIncludeDirectories";
+const char _AdditionalLibraryDirectories[] = "AdditionalLibraryDirectories";
+const char _AdditionalOptions[] = "AdditionalOptions";
+const char _AdditionalUsingDirectories[] = "AdditionalUsingDirectories";
+const char _AssemblerListingLocation[] = "AssemblerListingLocation";
+const char _AssemblerOutput[] = "AssemblerOutput";
+const char _ATLMinimizesCRunTimeLibraryUsage[] = "ATLMinimizesCRunTimeLibraryUsage";
+const char _BaseAddress[] = "BaseAddress";
+const char _BasicRuntimeChecks[] = "BasicRuntimeChecks";
+const char _BrowseInformation[] = "BrowseInformation";
+const char _BrowseInformationFile[] = "BrowseInformationFile";
+const char _BufferSecurityCheck[] = "BufferSecurityCheck";
+const char _BuildBrowserInformation[] = "BuildBrowserInformation";
+const char _CPreprocessOptions[] = "CPreprocessOptions";
+const char _CallingConvention[] = "CallingConvention";
+const char _CharacterSet[] = "CharacterSet";
+const char _CommandLine[] = "CommandLine";
+const char _CompileAs[] = "CompileAs";
+const char _CompileAsManaged[] = "CompileAsManaged";
+const char _CompileOnly[] = "CompileOnly";
+const char _ConfigurationType[] = "ConfigurationType";
+const char _Culture[] = "Culture";
+const char _DLLDataFileName[] = "DLLDataFileName";
+const char _DebugInformationFormat[] = "DebugInformationFormat";
+const char _DefaultCharIsUnsigned[] = "DefaultCharIsUnsigned";
+const char _DefaultCharType[] = "DefaultCharType";
+const char _DelayLoadDLLs[] = "DelayLoadDLLs";
+const char _DeleteExtensionsOnClean[] = "DeleteExtensionsOnClean";
+const char _Description[] = "Description";
+const char _Detect64BitPortabilityProblems[] = "Detect64BitPortabilityProblems";
+const char _DisableLanguageExtensions[] = "DisableLanguageExtensions";
+const char _DisableSpecificWarnings[] = "DisableSpecificWarnings";
+const char _EnableCOMDATFolding[] = "EnableCOMDATFolding";
+const char _EnableErrorChecks[] = "EnableErrorChecks";
+const char _EnableEnhancedInstructionSet[] = "EnableEnhancedInstructionSet";
+const char _EnableFiberSafeOptimizations[] = "EnableFiberSafeOptimizations";
+const char _EnableFunctionLevelLinking[] = "EnableFunctionLevelLinking";
+const char _EnableIntrinsicFunctions[] = "EnableIntrinsicFunctions";
+const char _EntryPointSymbol[] = "EntryPointSymbol";
+const char _ErrorCheckAllocations[] = "ErrorCheckAllocations";
+const char _ErrorCheckBounds[] = "ErrorCheckBounds";
+const char _ErrorCheckEnumRange[] = "ErrorCheckEnumRange";
+const char _ErrorCheckRefPointers[] = "ErrorCheckRefPointers";
+const char _ErrorCheckStubData[] = "ErrorCheckStubData";
+const char _ExceptionHandling[] = "ExceptionHandling";
+const char _ExcludedFromBuild[] = "ExcludedFromBuild";
+const char _ExpandAttributedSource[] = "ExpandAttributedSource";
+const char _ExportNamedFunctions[] = "ExportNamedFunctions";
+const char _FavorSizeOrSpeed[] = "FavorSizeOrSpeed";
+const char _FloatingPointModel[] = "FloatingPointModel";
+const char _FloatingPointExceptions[] = "FloatingPointExceptions";
+const char _ForceConformanceInForLoopScope[] = "ForceConformanceInForLoopScope";
+const char _ForceSymbolReferences[] = "ForceSymbolReferences";
+const char _ForcedIncludeFiles[] = "ForcedIncludeFiles";
+const char _ForcedUsingFiles[] = "ForcedUsingFiles";
+const char _FullIncludePath[] = "FullIncludePath";
+const char _FunctionOrder[] = "FunctionOrder";
+const char _GenerateDebugInformation[] = "GenerateDebugInformation";
+const char _GenerateMapFile[] = "GenerateMapFile";
+const char _GeneratePreprocessedFile[] = "GeneratePreprocessedFile";
+const char _GenerateStublessProxies[] = "GenerateStublessProxies";
+const char _GenerateTypeLibrary[] = "GenerateTypeLibrary";
+const char _GlobalOptimizations[] = "GlobalOptimizations";
+const char _HeaderFileName[] = "HeaderFileName";
+const char _HeapCommitSize[] = "HeapCommitSize";
+const char _HeapReserveSize[] = "HeapReserveSize";
+const char _IgnoreAllDefaultLibraries[] = "IgnoreAllDefaultLibraries";
+const char _IgnoreDefaultLibraryNames[] = "IgnoreDefaultLibraryNames";
+const char _IgnoreEmbeddedIDL[] = "IgnoreEmbeddedIDL";
+const char _IgnoreImportLibrary[] = "IgnoreImportLibrary";
+const char _IgnoreStandardIncludePath[] = "IgnoreStandardIncludePath";
+const char _ImportLibrary[] = "ImportLibrary";
+const char _ImproveFloatingPointConsistency[] = "ImproveFloatingPointConsistency";
+const char _InlineFunctionExpansion[] = "InlineFunctionExpansion";
+const char _InterfaceIdentifierFileName[] = "InterfaceIdentifierFileName";
+const char _IntermediateDirectory[] = "IntermediateDirectory";
+const char _KeepComments[] = "KeepComments";
+const char _LargeAddressAware[] = "LargeAddressAware";
+const char _LinkDLL[] = "LinkDLL";
+const char _LinkIncremental[] = "LinkIncremental";
+const char _LinkTimeCodeGeneration[] = "LinkTimeCodeGeneration";
+const char _LinkToManagedResourceFile[] = "LinkToManagedResourceFile";
+const char _MapExports[] = "MapExports";
+const char _MapFileName[] = "MapFileName";
+const char _MapLines[] = "MapLines ";
+const char _MergeSections[] = "MergeSections";
+const char _MergedIDLBaseFileName[] = "MergedIDLBaseFileName";
+const char _MidlCommandFile[] = "MidlCommandFile";
+const char _MinimalRebuild[] = "MinimalRebuild";
+const char _MkTypLibCompatible[] = "MkTypLibCompatible";
+const char _ModuleDefinitionFile[] = "ModuleDefinitionFile";
+const char _Name[] = "Name";
+const char _ObjectFile[] = "ObjectFile";
+const char _OmitFramePointers[] = "OmitFramePointers";
+const char _OpenMP[] = "OpenMP";
+const char _Optimization[] = "Optimization ";
+const char _OptimizeForProcessor[] = "OptimizeForProcessor";
+const char _OptimizeForWindows98[] = "OptimizeForWindows98";
+const char _OptimizeForWindowsApplication[] = "OptimizeForWindowsApplication";
+const char _OptimizeReferences[] = "OptimizeReferences";
+const char _OutputDirectory[] = "OutputDirectory";
+const char _OutputFile[] = "OutputFile";
+const char _Outputs[] = "Outputs";
+const char _ParseFiles[] = "ParseFiles";
+const char _PrecompiledHeaderFile[] = "PrecompiledHeaderFile";
+const char _PrecompiledHeaderThrough[] = "PrecompiledHeaderThrough";
+const char _PreprocessorDefinitions[] = "PreprocessorDefinitions";
+const char _PrimaryOutput[] = "PrimaryOutput";
+const char _ProjectGUID[] = "ProjectGUID";
+const char _Keyword[] = "Keyword";
+const char _ProjectType[] = "ProjectType";
+const char _ProgramDatabase[] = "ProgramDatabase";
+const char _ProgramDataBaseFileName[] = "ProgramDataBaseFileName";
+const char _ProgramDatabaseFile[] = "ProgramDatabaseFile";
+const char _ProxyFileName[] = "ProxyFileName";
+const char _RedirectOutputAndErrors[] = "RedirectOutputAndErrors";
+const char _RegisterOutput[] = "RegisterOutput";
+const char _RelativePath[] = "RelativePath";
+const char _RemoteDirectory[] = "RemoteDirectory";
+const char _ResourceOnlyDLL[] = "ResourceOnlyDLL";
+const char _ResourceOutputFileName[] = "ResourceOutputFileName";
+const char _RuntimeLibrary[] = "RuntimeLibrary";
+const char _RuntimeTypeInfo[] = "RuntimeTypeInfo";
+const char _SccProjectName[] = "SccProjectName";
+const char _SccLocalPath[] = "SccLocalPath";
+const char _SetChecksum[] = "SetChecksum";
+const char _ShowIncludes[] = "ShowIncludes";
+const char _ShowProgress[] = "ShowProgress";
+const char _SmallerTypeCheck[] = "SmallerTypeCheck";
+const char _StackCommitSize[] = "StackCommitSize";
+const char _StackReserveSize[] = "StackReserveSize";
+const char _StringPooling[] = "StringPooling";
+const char _StripPrivateSymbols[] = "StripPrivateSymbols";
+const char _StructMemberAlignment[] = "StructMemberAlignment";
+const char _SubSystem[] = "SubSystem";
+const char _SupportUnloadOfDelayLoadedDLL[] = "SupportUnloadOfDelayLoadedDLL";
+const char _SuppressStartupBanner[] = "SuppressStartupBanner";
+const char _SwapRunFromCD[] = "SwapRunFromCD";
+const char _SwapRunFromNet[] = "SwapRunFromNet";
+const char _TargetEnvironment[] = "TargetEnvironment";
+const char _TargetMachine[] = "TargetMachine";
+const char _TerminalServerAware[] = "TerminalServerAware";
+const char _Path[] = "Path";
+const char _TreatWChar_tAsBuiltInType[] = "TreatWChar_tAsBuiltInType";
+const char _TurnOffAssemblyGeneration[] = "TurnOffAssemblyGeneration";
+const char _TypeLibraryFile[] = "TypeLibraryFile";
+const char _TypeLibraryName[] = "TypeLibraryName";
+const char _TypeLibraryResourceID[] = "TypeLibraryResourceID";
+const char _UndefineAllPreprocessorDefinitions[]= "UndefineAllPreprocessorDefinitions";
+const char _UndefinePreprocessorDefinitions[] = "UndefinePreprocessorDefinitions";
+const char _UniqueIdentifier[] = "UniqueIdentifier";
+const char _UseOfATL[] = "UseOfATL";
+const char _UseOfMfc[] = "UseOfMfc";
+const char _UsePrecompiledHeader[] = "UsePrecompiledHeader";
+const char _ValidateParameters[] = "ValidateParameters";
+const char _VCCLCompilerTool[] = "VCCLCompilerTool";
+const char _VCLibrarianTool[] = "VCLibrarianTool";
+const char _VCLinkerTool[] = "VCLinkerTool";
+const char _VCCustomBuildTool[] = "VCCustomBuildTool";
+const char _VCResourceCompilerTool[] = "VCResourceCompilerTool";
+const char _VCMIDLTool[] = "VCMIDLTool";
+const char _Version[] = "Version";
+const char _WarnAsError[] = "WarnAsError";
+const char _WarningLevel[] = "WarningLevel";
+const char _WholeProgramOptimization[] = "WholeProgramOptimization";
+const char _CompileForArchitecture[] = "CompileForArchitecture";
+const char _InterworkCalls[] = "InterworkCalls";
+
+// XmlOutput stream functions ------------------------------
+inline XmlOutput::xml_output attrT(const char *name, const triState v)
+{
+ if(v == unset)
+ return noxml();
+ return attr(name, (v == _True ? "true" : "false"));
+}
+
+inline XmlOutput::xml_output attrE(const char *name, int v)
+{
+ return attr(name, QString::number(v));
+}
+
+/*ifNot version*/
+inline XmlOutput::xml_output attrE(const char *name, int v, int ifn)
+{
+ if (v == ifn)
+ return noxml();
+ return attr(name, QString::number(v));
+}
+
+inline XmlOutput::xml_output attrL(const char *name, qint64 v)
+{
+ return attr(name, QString::number(v));
+}
+
+/*ifNot version*/
+inline XmlOutput::xml_output attrL(const char *name, qint64 v, qint64 ifn)
+{
+ if (v == ifn)
+ return noxml();
+ return attr(name, QString::number(v));
+}
+
+inline XmlOutput::xml_output attrS(const char *name, const QString &v)
+{
+ if(v.isEmpty())
+ return noxml();
+ return attr(name, v);
+}
+
+inline XmlOutput::xml_output attrX(const char *name, const QStringList &v, const char *s = ",")
+{
+ if(v.isEmpty())
+ return noxml();
+ return attr(name, v.join(s));
+}
+
+triState operator!(const triState &rhs)
+{
+ if (rhs == unset)
+ return rhs;
+ triState lhs = (rhs == _True ? _False : _True);
+ return lhs;
+}
+
+// VCToolBase -------------------------------------------------
+QStringList VCToolBase::fixCommandLine(const QString &input)
+{
+ // The splitting regexp is a bit bizarre for backwards compat reasons (why else ...).
+ return input.split(QRegExp(QLatin1String("\n\t|\r\\\\h|\r\n")));
+}
+
+static QString vcCommandSeparator()
+{
+ // MSVC transforms the build tree into a single batch file, simply pasting the contents
+ // of the custom commands into it, and putting an "if errorlevel goto" statement behind it.
+ // As we want every sub-command to be error-checked (as is done by makefile-based
+ // backends), we insert the checks ourselves, using the undocumented jump target.
+ static QString cmdSep =
+ QLatin1String("&#x000D;&#x000A;if errorlevel 1 goto VCReportError&#x000D;&#x000A;");
+ return cmdSep;
+}
+
+// VCCLCompilerTool -------------------------------------------------
+VCCLCompilerTool::VCCLCompilerTool()
+ : AssemblerOutput(asmListingNone),
+ BasicRuntimeChecks(runtimeBasicCheckNone),
+ BrowseInformation(brInfoNone),
+ BufferSecurityCheck(_False),
+ CallingConvention(callConventionDefault),
+ CompileAs(compileAsDefault),
+ CompileAsManaged(managedDefault),
+ CompileOnly(unset),
+ DebugInformationFormat(debugDisabled),
+ DefaultCharIsUnsigned(unset),
+ Detect64BitPortabilityProblems(unset),
+ DisableLanguageExtensions(unset),
+ EnableEnhancedInstructionSet(archNotSet),
+ EnableFiberSafeOptimizations(unset),
+ EnableFunctionLevelLinking(unset),
+ EnableIntrinsicFunctions(unset),
+ ExceptionHandling(ehDefault),
+ ExpandAttributedSource(unset),
+ FavorSizeOrSpeed(favorNone),
+ FloatingPointModel(floatingPointNotSet),
+ FloatingPointExceptions(unset),
+ ForceConformanceInForLoopScope(unset),
+ GeneratePreprocessedFile(preprocessNo),
+ PreprocessSuppressLineNumbers(unset),
+ GlobalOptimizations(unset),
+ IgnoreStandardIncludePath(unset),
+ ImproveFloatingPointConsistency(unset),
+ InlineFunctionExpansion(expandDefault),
+ KeepComments(unset),
+ MinimalRebuild(unset),
+ OmitDefaultLibName(unset),
+ OmitFramePointers(unset),
+ OpenMP(unset),
+ Optimization(optimizeCustom),
+ OptimizeForProcessor(procOptimizeBlended),
+ OptimizeForWindowsApplication(unset),
+ ProgramDataBaseFileName(""),
+ RuntimeLibrary(rtMultiThreaded),
+ RuntimeTypeInfo(unset),
+ ShowIncludes(unset),
+ SmallerTypeCheck(unset),
+ StringPooling(unset),
+ StructMemberAlignment(alignNotSet),
+ SuppressStartupBanner(unset),
+ TreatWChar_tAsBuiltInType(unset),
+ TurnOffAssemblyGeneration(unset),
+ UndefineAllPreprocessorDefinitions(unset),
+ UsePrecompiledHeader(pchUnset),
+ UseUnicodeForAssemblerListing(unset),
+ WarnAsError(unset),
+ WarningLevel(warningLevel_0),
+ WholeProgramOptimization(unset),
+ CompileForArchitecture(archUnknown),
+ InterworkCalls(unset),
+ EnablePREfast(unset),
+ DisplayFullPaths(unset),
+ MultiProcessorCompilation(unset),
+ GenerateXMLDocumentationFiles(unset),
+ CreateHotpatchableImage(unset)
+{
+}
+
+/*
+ * Some values for the attribute UsePrecompiledHeader have changed from VS 2003 to VS 2005,
+ * see the following chart, so we need a function that transforms those values if we are
+ * using NET2005:
+ *
+ * Meaning 2003 2005
+ * -----------------------------------------
+ * Don't use PCH 0 0
+ * Create PCH (/Yc) 1 1
+ * Automatically generate (/YX) 2 (seems that it was removed)
+ * Use specific PCH (/Yu) 3 2
+ *
+ */
+inline XmlOutput::xml_output xformUsePrecompiledHeaderForNET2005(pchOption whatPch, DotNET compilerVersion)
+{
+ if (compilerVersion >= NET2005) {
+ if (whatPch == pchGenerateAuto) whatPch = (pchOption)0;
+ if (whatPch == pchUseUsingSpecific) whatPch = (pchOption)2;
+ }
+ return attrE(_UsePrecompiledHeader, whatPch, /*ifNot*/ pchUnset);
+}
+
+inline XmlOutput::xml_output xformExceptionHandlingNET2005(exceptionHandling eh, DotNET compilerVersion)
+{
+ if (eh == ehDefault)
+ return noxml();
+
+ if (compilerVersion >= NET2005)
+ return attrE(_ExceptionHandling, eh);
+
+ return attrS(_ExceptionHandling, (eh == ehNoSEH ? "true" : "false"));
+}
+
+bool VCCLCompilerTool::parseOption(const char* option)
+{
+ // skip index 0 ('/' or '-')
+ char first = option[1];
+ char second = option[2];
+ char third = option[3];
+ char fourth = option[4];
+ bool found = true;
+
+ switch (first) {
+ case '?':
+ case 'h':
+ if(second == 'o' && third == 't' && fourth == 'p') {
+ CreateHotpatchableImage = _True;
+ break;
+ }
+ qWarning("Generator: Option '/?', '/help': MSVC.NET projects do not support outputting help info");
+ found = false;
+ break;
+ case '@':
+ qWarning("Generator: Option '/@': MSVC.NET projects do not support the use of a response file");
+ found = false;
+ break;
+ case 'l':
+ qWarning("Generator: Option '/link': qmake generator does not support passing link options through the compiler tool");
+ found = false;
+ break;
+ case 'A':
+ if(second != 'I') {
+ found = false; break;
+ }
+ AdditionalUsingDirectories += option+3;
+ break;
+ case 'C':
+ KeepComments = _True;
+ break;
+ case 'D':
+ PreprocessorDefinitions += option+2;
+ break;
+ case 'E':
+ if(second == 'H') {
+ QByteArray opt(option + 2);
+ if (opt.contains('a') && !opt.contains('s') && !opt.contains('c'))
+ ExceptionHandling = ehSEH;
+ else if (!opt.contains('a') && opt.contains("s-") && opt.contains("c-"))
+ ExceptionHandling = ehNone;
+ else if (!opt.contains('a') && opt.contains('s') && opt.contains('c'))
+ ExceptionHandling = ehNoSEH;
+ else {
+ // ExceptionHandling must be false, or it will override
+ // with an /EHsc option
+ ExceptionHandling = ehNone;
+ AdditionalOptions += option;
+ }
+ if (config->CompilerVersion < NET2005
+ && ExceptionHandling == ehSEH) {
+ ExceptionHandling = ehNone;
+ AdditionalOptions += option;
+ }
+ break;
+ } else if (second == 'P') {
+ PreprocessSuppressLineNumbers = _True;
+ }
+ GeneratePreprocessedFile = preprocessYes;
+ break;
+ case 'F':
+ if(second <= '9' && second >= '0') {
+ AdditionalOptions += option;
+ break;
+ } else {
+ switch (second) {
+ case 'A':
+ if(third == 'c') {
+ AssemblerOutput = asmListingAsmMachine;
+ if(fourth == 's')
+ AssemblerOutput = asmListingAsmMachineSrc;
+ } else if(third == 's') {
+ AssemblerOutput = asmListingAsmSrc;
+ } else if (third == 'u') {
+ UseUnicodeForAssemblerListing = _True;
+ } else {
+ AssemblerOutput = asmListingAssemblyOnly;
+ }
+ break;
+ case 'C':
+ DisplayFullPaths = _True;
+ break;
+ case 'a':
+ AssemblerListingLocation = option+3;
+ break;
+ case 'I':
+ ForcedIncludeFiles += option+3;
+ break;
+ case 'i':
+ PreprocessOutputPath += option+3;
+ break;
+ case 'R':
+ BrowseInformation = brAllInfo;
+ BrowseInformationFile = option+3;
+ break;
+ case 'r':
+ BrowseInformation = brNoLocalSymbols;
+ BrowseInformationFile = option+3;
+ break;
+ case 'U':
+ ForcedUsingFiles += option+3;
+ break;
+ case 'd':
+ ProgramDataBaseFileName = option+3;
+ break;
+ case 'e':
+ OutputFile = option+3;
+ break;
+ case 'm':
+ AdditionalOptions += option;
+ break;
+ case 'o':
+ ObjectFile = option+3;
+ break;
+ case 'p':
+ PrecompiledHeaderFile = option+3;
+ break;
+ case 'x':
+ ExpandAttributedSource = _True;
+ break;
+ default:
+ found = false; break;
+ }
+ }
+ break;
+ case 'G':
+ switch (second) {
+ case '3':
+ case '4':
+ qWarning("Option '/G3' and '/G4' were phased out in Visual C++ 5.0");
+ found = false; break;
+ case '5':
+ OptimizeForProcessor = procOptimizePentium;
+ break;
+ case '6':
+ case 'B':
+ OptimizeForProcessor = procOptimizePentiumProAndAbove;
+ break;
+ case '7':
+ OptimizeForProcessor = procOptimizePentium4AndAbove;
+ break;
+ case 'A':
+ OptimizeForWindowsApplication = _True;
+ break;
+ case 'F':
+ StringPooling = _True;
+ break;
+ case 'H':
+ AdditionalOptions += option;
+ break;
+ case 'L':
+ WholeProgramOptimization = _True;
+ if(third == '-')
+ WholeProgramOptimization = _False;
+ break;
+ case 'R':
+ RuntimeTypeInfo = _True;
+ if(third == '-')
+ RuntimeTypeInfo = _False;
+ break;
+ case 'S':
+ BufferSecurityCheck = _True;
+ if(third == '-')
+ BufferSecurityCheck = _False;
+ break;
+ case 'T':
+ EnableFiberSafeOptimizations = _True;
+ break;
+ case 'X':
+ // Same as the /EHsc option, which is Exception Handling without SEH
+ ExceptionHandling = ehNoSEH;
+ if (third == '-')
+ ExceptionHandling = ehNone;
+ break;
+ case 'Z':
+ case 'e':
+ case 'h':
+ AdditionalOptions += option;
+ break;
+ case 'd':
+ CallingConvention = callConventionCDecl;
+ break;
+ case 'f':
+ StringPooling = _True;
+ AdditionalOptions += option;
+ break;
+ case 'm':
+ MinimalRebuild = _True;
+ if(third == '-')
+ MinimalRebuild = _False;
+ break;
+ case 'r':
+ CallingConvention = callConventionFastCall;
+ break;
+ case 's':
+ // Warning: following [num] is not used,
+ // were should we put it?
+ BufferSecurityCheck = _True;
+ break;
+ case 'y':
+ EnableFunctionLevelLinking = _True;
+ break;
+ case 'z':
+ CallingConvention = callConventionStdCall;
+ break;
+ default:
+ found = false; break;
+ }
+ break;
+ case 'H':
+ AdditionalOptions += option;
+ break;
+ case 'I':
+ AdditionalIncludeDirectories += option+2;
+ break;
+ case 'J':
+ DefaultCharIsUnsigned = _True;
+ break;
+ case 'L':
+ if(second == 'D') {
+ AdditionalOptions += option;
+ break;
+ }
+ found = false; break;
+ case 'M':
+ if(second == 'D') {
+ RuntimeLibrary = rtMultiThreadedDLL;
+ if(third == 'd')
+ RuntimeLibrary = rtMultiThreadedDebugDLL;
+ break;
+ } else if(second == 'L') {
+ RuntimeLibrary = rtSingleThreaded;
+ if(third == 'd')
+ RuntimeLibrary = rtSingleThreadedDebug;
+ break;
+ } else if(second == 'T') {
+ RuntimeLibrary = rtMultiThreaded;
+ if(third == 'd')
+ RuntimeLibrary = rtMultiThreadedDebug;
+ break;
+ } else if (second == 'P') {
+ if (config->CompilerVersion >= NET2005) {
+ AdditionalOptions += option;
+ } else if (config->CompilerVersion >= NET2010) {
+ MultiProcessorCompilation = _True;
+ MultiProcessorCompilationProcessorCount = option+3;
+ } else {
+ warn_msg(WarnLogic, "/MP option is not supported in Visual C++ < 2005, ignoring.");
+ }
+ break;
+ }
+ found = false; break;
+ case 'O':
+ switch (second) {
+ case '1':
+ Optimization = optimizeMinSpace;
+ break;
+ case '2':
+ Optimization = optimizeMaxSpeed;
+ break;
+ case 'a':
+ AdditionalOptions += option;
+ break;
+ case 'b':
+ if(third == '0')
+ InlineFunctionExpansion = expandDisable;
+ else if(third == '1')
+ InlineFunctionExpansion = expandOnlyInline;
+ else if(third == '2')
+ InlineFunctionExpansion = expandAnySuitable;
+ else
+ found = false;
+ break;
+ case 'd':
+ Optimization = optimizeDisabled;
+ break;
+ case 'g':
+ GlobalOptimizations = _True;
+ break;
+ case 'i':
+ EnableIntrinsicFunctions = _True;
+ break;
+ case 'p':
+ ImproveFloatingPointConsistency = _True;
+ if(third == '-')
+ ImproveFloatingPointConsistency = _False;
+ break;
+ case 's':
+ FavorSizeOrSpeed = favorSize;
+ break;
+ case 't':
+ FavorSizeOrSpeed = favorSpeed;
+ break;
+ case 'w':
+ AdditionalOptions += option;
+ break;
+ case 'x':
+ Optimization = optimizeFull;
+ break;
+ case 'y':
+ OmitFramePointers = _True;
+ if(third == '-')
+ OmitFramePointers = _False;
+ break;
+ default:
+ found = false; break;
+ }
+ break;
+ case 'P':
+ GeneratePreprocessedFile = preprocessYes;
+ break;
+ case 'Q':
+ if(second == 'I') {
+ AdditionalOptions += option;
+ break;
+ } else if (second == 'R') {
+ QString opt = option + 3;
+ if (opt == "interwork-return") {
+ InterworkCalls = _True;
+ break;
+ } else if (opt == "arch4") {
+ CompileForArchitecture = archArmv4;
+ break;
+ } else if (opt == "arch5") {
+ CompileForArchitecture = archArmv5;
+ break;
+ } else if (opt == "arch4T") {
+ CompileForArchitecture = archArmv4T;
+ break;
+ } else if (opt == "arch5T") {
+ CompileForArchitecture = archArmv5T;
+ break;
+ }
+ } else if (second == 'M') {
+ QString opt = option + 3;
+ if (opt == "mips1") {
+ CompileForArchitecture = archMips1;
+ break;
+ }
+ else if (opt == "mips2") {
+ CompileForArchitecture = archMips2;
+ break;
+ }
+ else if (opt == "mips3") {
+ CompileForArchitecture = archMips3;
+ break;
+ }
+ else if (opt == "mips4") {
+ CompileForArchitecture = archMips4;
+ break;
+ }
+ else if (opt == "mips5") {
+ CompileForArchitecture = archMips5;
+ break;
+ }
+ else if (opt == "mips16") {
+ CompileForArchitecture = archMips16;
+ break;
+ }
+ else if (opt == "mips32") {
+ CompileForArchitecture = archMips32;
+ break;
+ }
+ else if (opt == "mips64") {
+ CompileForArchitecture = archMips64;
+ break;
+ }
+ }
+ found = false; break;
+ case 'R':
+ if(second == 'T' && third == 'C') {
+ if(fourth == '1')
+ BasicRuntimeChecks = runtimeBasicCheckAll;
+ else if(fourth == 'c')
+ SmallerTypeCheck = _True;
+ else if(fourth == 's')
+ BasicRuntimeChecks = runtimeCheckStackFrame;
+ else if(fourth == 'u')
+ BasicRuntimeChecks = runtimeCheckUninitVariables;
+ else
+ found = false; break;
+ }
+ break;
+ case 'T':
+ if(second == 'C') {
+ CompileAs = compileAsC;
+ } else if(second == 'P') {
+ CompileAs = compileAsCPlusPlus;
+ } else {
+ qWarning("Generator: Options '/Tp<filename>' and '/Tc<filename>' are not supported by qmake");
+ found = false; break;
+ }
+ break;
+ case 'U':
+ UndefinePreprocessorDefinitions += option+2;
+ break;
+ case 'V':
+ AdditionalOptions += option;
+ break;
+ case 'W':
+ switch (second) {
+ case 'a':
+ case '4':
+ WarningLevel = warningLevel_4;
+ break;
+ case '3':
+ WarningLevel = warningLevel_3;
+ break;
+ case '2':
+ WarningLevel = warningLevel_2;
+ break;
+ case '1':
+ WarningLevel = warningLevel_1;
+ break;
+ case '0':
+ WarningLevel = warningLevel_0;
+ break;
+ case 'L':
+ AdditionalOptions += option;
+ break;
+ case 'X':
+ WarnAsError = _True;
+ break;
+ case 'p':
+ if(third == '6' && fourth == '4') {
+ if (config->CompilerVersion >= NET2010) {
+ // Deprecated for VS2010 but can be used under Additional Options.
+ AdditionalOptions += option;
+ } else {
+ Detect64BitPortabilityProblems = _True;
+ }
+ break;
+ }
+ // Fallthrough
+ default:
+ found = false; break;
+ }
+ break;
+ case 'X':
+ IgnoreStandardIncludePath = _True;
+ break;
+ case 'Y':
+ switch (second) {
+ case '\0':
+ case '-':
+ AdditionalOptions += option;
+ break;
+ case 'X':
+ UsePrecompiledHeader = pchGenerateAuto;
+ PrecompiledHeaderThrough = option+3;
+ break;
+ case 'c':
+ UsePrecompiledHeader = pchCreateUsingSpecific;
+ PrecompiledHeaderThrough = option+3;
+ break;
+ case 'd':
+ case 'l':
+ AdditionalOptions += option;
+ break;
+ case 'u':
+ UsePrecompiledHeader = pchUseUsingSpecific;
+ PrecompiledHeaderThrough = option+3;
+ break;
+ default:
+ found = false; break;
+ }
+ break;
+ case 'Z':
+ switch (second) {
+ case '7':
+ DebugInformationFormat = debugOldStyleInfo;
+ break;
+ case 'I':
+ DebugInformationFormat = debugEditAndContinue;
+ break;
+ case 'd':
+ DebugInformationFormat = debugLineInfoOnly;
+ break;
+ case 'i':
+ DebugInformationFormat = debugEnabled;
+ break;
+ case 'l':
+ OmitDefaultLibName = _True;
+ break;
+ case 'a':
+ DisableLanguageExtensions = _True;
+ break;
+ case 'e':
+ DisableLanguageExtensions = _False;
+ break;
+ case 'c':
+ if(third == ':') {
+ const char *c = option + 4;
+ // Go to the end of the option
+ while ( *c != '\0' && *c != ' ' && *c != '-')
+ ++c;
+ if(fourth == 'f')
+ ForceConformanceInForLoopScope = ((*c) == '-' ? _False : _True);
+ else if(fourth == 'w')
+ TreatWChar_tAsBuiltInType = ((*c) == '-' ? _False : _True);
+ else
+ found = false;
+ } else {
+ found = false; break;
+ }
+ break;
+ case 'g':
+ case 'm':
+ case 's':
+ AdditionalOptions += option;
+ break;
+ case 'p':
+ switch (third)
+ {
+ case '\0':
+ case '1':
+ StructMemberAlignment = alignSingleByte;
+ if(fourth == '6')
+ StructMemberAlignment = alignSixteenBytes;
+ break;
+ case '2':
+ StructMemberAlignment = alignTwoBytes;
+ break;
+ case '4':
+ StructMemberAlignment = alignFourBytes;
+ break;
+ case '8':
+ StructMemberAlignment = alignEightBytes;
+ break;
+ default:
+ found = false; break;
+ }
+ break;
+ default:
+ found = false; break;
+ }
+ break;
+ case 'a':
+ if (second == 'r' && third == 'c' && fourth == 'h') {
+ if (option[5] == ':') {
+ const char *o = option;
+ if (o[6] == 'S' && o[7] == 'S' && o[8] == 'E') {
+ EnableEnhancedInstructionSet = o[9] == '2' ? archSSE2 : archSSE;
+ break;
+ }
+ }
+ } else if (second == 'n' && third == 'a' && fourth == 'l') {
+ EnablePREfast = _True;
+ break;
+ }
+ found = false;
+ break;
+ case 'b': // see http://msdn2.microsoft.com/en-us/library/ms173499.aspx
+ if (second == 'i' && third == 'g' && fourth == 'o') {
+ const char *o = option;
+ if (o[5] == 'b' && o[6] == 'j') {
+ AdditionalOptions += option;
+ break;
+ }
+ }
+ found = false;
+ break;
+ case 'c':
+ if(second == '\0') {
+ CompileOnly = _True;
+ } else if(second == 'l') {
+ if (config->CompilerVersion < NET2005) {
+ if(*(option+5) == 'n') {
+ CompileAsManaged = managedAssemblyPure;
+ TurnOffAssemblyGeneration = _True;
+ } else if(*(option+5) == 'p') {
+ CompileAsManaged = managedAssemblyPure;
+ warn_msg(WarnLogic, "/clr:pure option only for .NET >= 2005, using /clr");
+ } else if(*(option+5) == 's') {
+ CompileAsManaged = managedAssemblyPure;
+ warn_msg(WarnLogic, "/clr:safe option only for .NET >= 2005, using /clr");
+ } else if(*(option+5) == 'o') {
+ CompileAsManaged = managedAssemblyPure;
+ warn_msg(WarnLogic, "/clr:oldSyntax option only for .NET >= 2005, using /clr");
+ } else if(*(option+5) == 'i') {
+ CompileAsManaged = managedAssemblyPure;
+ warn_msg(WarnLogic, "initialAppDomain enum value unknown, using /crl");
+ } else {
+ CompileAsManaged = managedAssemblyPure;
+ }
+ } else {
+ if(*(option+5) == 'n') {
+ CompileAsManaged = managedAssembly;
+ TurnOffAssemblyGeneration = _True;
+ } else if(*(option+5) == 'p') {
+ CompileAsManaged = managedAssemblyPure;
+ } else if(*(option+5) == 's') {
+ CompileAsManaged = managedAssemblySafe;
+ } else if(*(option+5) == 'o') {
+ CompileAsManaged = managedAssemblyOldSyntax;
+ } else if(*(option+5) == 'i') {
+ CompileAsManaged = managedAssembly;
+ warn_msg(WarnLogic, "initialAppDomain enum value unknown, using /crl default");
+ } else {
+ CompileAsManaged = managedAssembly;
+ }
+ }
+ } else {
+ found = false; break;
+ }
+ break;
+ case 'd':
+ if (second == 'r') {
+ CompileAsManaged = managedAssembly;
+ break;
+ } else if (second != 'o' && third == 'c') {
+ GenerateXMLDocumentationFiles = _True;
+ XMLDocumentationFileName += option+4;
+ break;
+ }
+ found = false;
+ break;
+ case 'e':
+ if (second == 'r' && third == 'r' && fourth == 'o') {
+ if (option[12] == ':') {
+ if ( option[13] == 'n') {
+ ErrorReporting = "None";
+ } else if (option[13] == 'p') {
+ ErrorReporting = "Prompt";
+ } else if (option[13] == 'q') {
+ ErrorReporting = "Queue";
+ } else if (option[13] == 's') {
+ ErrorReporting = "Send";
+ } else {
+ found = false;
+ }
+ break;
+ }
+ }
+ found = false;
+ break;
+ case 'f':
+ if(second == 'p' && third == ':') {
+ // Go to the end of the option
+ const char *c = option + 4;
+ while (*c != '\0' && *c != ' ' && *c != '-')
+ ++c;
+ switch (fourth) {
+ case 'e':
+ FloatingPointExceptions = ((*c) == '-' ? _False : _True);
+ break;
+ case 'f':
+ FloatingPointModel = floatingPointFast;
+ break;
+ case 'p':
+ FloatingPointModel = floatingPointPrecise;
+ break;
+ case 's':
+ FloatingPointModel = floatingPointStrict;
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+ break;
+ case 'n':
+ if(second == 'o' && third == 'B' && fourth == 'o') {
+ AdditionalOptions += "/noBool";
+ break;
+ }
+ if(second == 'o' && third == 'l' && fourth == 'o') {
+ SuppressStartupBanner = _True;
+ break;
+ }
+ found = false; break;
+ case 'o':
+ if (second == 'p' && third == 'e' && fourth == 'n') {
+ OpenMP = _True;
+ break;
+ }
+ found = false; break;
+ case 's':
+ if(second == 'h' && third == 'o' && fourth == 'w') {
+ ShowIncludes = _True;
+ break;
+ }
+ found = false; break;
+ case 'u':
+ UndefineAllPreprocessorDefinitions = _True;
+ break;
+ case 'v':
+ if(second == 'd' || second == 'm') {
+ AdditionalOptions += option;
+ break;
+ }
+ found = false; break;
+ case 'w':
+ switch (second) {
+ case '\0':
+ WarningLevel = warningLevel_0;
+ break;
+ case 'd':
+ DisableSpecificWarnings += option+3;
+ break;
+ default:
+ AdditionalOptions += option;
+ }
+ break;
+ default:
+ AdditionalOptions += option;
+ break;
+ }
+ if(!found) {
+ warn_msg(WarnLogic, "Could not parse Compiler option: %s, added as AdditionalOption", option);
+ AdditionalOptions += option;
+ }
+ return true;
+}
+
+// VCLinkerTool -----------------------------------------------------
+VCLinkerTool::VCLinkerTool()
+ : DataExecutionPrevention(unset),
+ EnableCOMDATFolding(optFoldingDefault),
+ GenerateDebugInformation(unset),
+ GenerateMapFile(unset),
+ HeapCommitSize(-1),
+ HeapReserveSize(-1),
+ IgnoreAllDefaultLibraries(unset),
+ IgnoreEmbeddedIDL(unset),
+ IgnoreImportLibrary(_True),
+ LargeAddressAware(addrAwareDefault),
+ LinkDLL(unset),
+ LinkIncremental(linkIncrementalDefault),
+ LinkTimeCodeGeneration(optLTCGDefault),
+ MapExports(unset),
+ MapLines(unset),
+ OptimizeForWindows98(optWin98Default),
+ OptimizeReferences(optReferencesDefault),
+ RandomizedBaseAddress(unset),
+ RegisterOutput(unset),
+ ResourceOnlyDLL(unset),
+ SetChecksum(unset),
+ ShowProgress(linkProgressNotSet),
+ StackCommitSize(-1),
+ StackReserveSize(-1),
+ SubSystem(subSystemNotSet),
+ SupportUnloadOfDelayLoadedDLL(unset),
+ SuppressStartupBanner(unset),
+ SwapRunFromCD(unset),
+ SwapRunFromNet(unset),
+ TargetMachine(machineNotSet),
+ TerminalServerAware(termSvrAwareDefault),
+ TreatWarningsAsErrors(unset),
+ TurnOffAssemblyGeneration(unset),
+ TypeLibraryResourceID(0),
+ GenerateManifest(unset),
+ EnableUAC(unset),
+ UACUIAccess(unset),
+ SectionAlignment(-1),
+ PreventDllBinding(unset),
+ AllowIsolation(unset),
+ AssemblyDebug(unset),
+ CLRUnmanagedCodeCheck(unset),
+ DelaySign(unset)
+{
+}
+
+// Hashing routine to do fast option lookups ----
+// Slightly rewritten to stop on ':' ',' and '\0'
+// Original routine in qtranslator.cpp ----------
+static uint elfHash(const char* name)
+{
+ const uchar *k;
+ uint h = 0;
+ uint g;
+
+ if(name) {
+ k = (const uchar *) name;
+ while((*k) &&
+ (*k)!= ':' &&
+ (*k)!=',' &&
+ (*k)!=' ') {
+ h = (h << 4) + *k++;
+ if((g = (h & 0xf0000000)) != 0)
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ }
+ if(!h)
+ h = 1;
+ return h;
+}
+
+//#define USE_DISPLAY_HASH
+#ifdef USE_DISPLAY_HASH
+static void displayHash(const char* str)
+{
+ printf("case 0x%07x: // %s\n break;\n", elfHash(str), str);
+}
+#endif
+
+bool VCLinkerTool::parseOption(const char* option)
+{
+#ifdef USE_DISPLAY_HASH
+ // Main options
+ displayHash("/ALIGN"); displayHash("/ALLOWBIND"); displayHash("/ASSEMBLYMODULE");
+ displayHash("/ASSEMBLYRESOURCE"); displayHash("/BASE"); displayHash("/DEBUG");
+ displayHash("/DEF"); displayHash("/DEFAULTLIB"); displayHash("/DELAY");
+ displayHash("/DELAYLOAD"); displayHash("/DLL"); displayHash("/DRIVER");
+ displayHash("/ENTRY"); displayHash("/EXETYPE"); displayHash("/EXPORT");
+ displayHash("/FIXED"); displayHash("/FORCE"); displayHash("/HEAP");
+ displayHash("/IDLOUT"); displayHash("/IGNORE"); displayHash("/IGNOREIDL"); displayHash("/IMPLIB");
+ displayHash("/INCLUDE"); displayHash("/INCREMENTAL"); displayHash("/LARGEADDRESSAWARE");
+ displayHash("/LIBPATH"); displayHash("/LTCG"); displayHash("/MACHINE");
+ displayHash("/MAP"); displayHash("/MAPINFO"); displayHash("/MERGE");
+ displayHash("/MIDL"); displayHash("/NOASSEMBLY"); displayHash("/NODEFAULTLIB");
+ displayHash("/NOENTRY"); displayHash("/NOLOGO"); displayHash("/OPT");
+ displayHash("/ORDER"); displayHash("/OUT"); displayHash("/PDB");
+ displayHash("/PDBSTRIPPED"); displayHash("/RELEASE"); displayHash("/SECTION");
+ displayHash("/STACK"); displayHash("/STUB"); displayHash("/SUBSYSTEM");
+ displayHash("/SWAPRUN"); displayHash("/TLBID"); displayHash("/TLBOUT");
+ displayHash("/TSAWARE"); displayHash("/VERBOSE"); displayHash("/VERSION");
+ displayHash("/VXD"); displayHash("/WS "); displayHash("/libpath");
+
+#endif
+#ifdef USE_DISPLAY_HASH
+ // Sub options
+ displayHash("UNLOAD"); displayHash("NOBIND"); displayHash("no"); displayHash("NOSTATUS"); displayHash("STATUS");
+ displayHash("AM33"); displayHash("ARM"); displayHash("CEE"); displayHash("EBC"); displayHash("IA64"); displayHash("X86"); displayHash("X64"); displayHash("M32R");
+ displayHash("MIPS"); displayHash("MIPS16"); displayHash("MIPSFPU"); displayHash("MIPSFPU16"); displayHash("MIPSR41XX"); displayHash("PPC");
+ displayHash("SH3"); displayHash("SH3DSP"); displayHash("SH4"); displayHash("SH5"); displayHash("THUMB"); displayHash("TRICORE"); displayHash("EXPORTS");
+ displayHash("LINES"); displayHash("REF"); displayHash("NOREF"); displayHash("ICF"); displayHash("WIN98"); displayHash("NOWIN98");
+ displayHash("CONSOLE"); displayHash("EFI_APPLICATION"); displayHash("EFI_BOOT_SERVICE_DRIVER"); displayHash("EFI_ROM"); displayHash("EFI_RUNTIME_DRIVER"); displayHash("NATIVE");
+ displayHash("POSIX"); displayHash("WINDOWS"); displayHash("WINDOWSCE"); displayHash("NET"); displayHash("CD"); displayHash("NO");
+#endif
+ bool found = true;
+ const uint optionHash = elfHash(option);
+ if (config->CompilerVersion < NET2010) {
+ switch (optionHash) {
+ case 0x3360dbe: // /ALIGN[:number]
+ case 0x1485c34: // /ALLOWBIND[:NO]
+ case 0x33aec94: // /FIXED[:NO]
+ case 0x7988f7e: // /SECTION:name,[E][R][W][S][D][K][L][P][X][,ALIGN=#]
+ case 0x0348992: // /STUB:filename
+ AdditionalOptions += option;
+ return true;
+ }
+ }
+
+ switch (optionHash) {
+ case 0x6b21972: // /DEFAULTLIB:library
+ case 0x396ea92: // /DRIVER[:UPONLY | :WDM]
+ case 0xaca9d75: // /EXETYPE[:DYNAMIC | :DEV386]
+ case 0x3ad5444: // /EXPORT:entryname[,@ordinal[,NONAME]][,DATA]
+ case 0x33b4675: // /FORCE:[MULTIPLE|UNRESOLVED]
+ case 0x3dc3455: // /IGNORE:number,number,number,number ### NOTE: This one is undocumented, but it is even used by Microsoft.
+ // In recent versions of the Microsoft linker they have disabled this undocumented feature.
+ case 0x0034bc4: // /VXD
+ AdditionalOptions += option;
+ break;
+ case 0x3360dbe: // /ALIGN[:number]
+ SectionAlignment = QString(option+7).toLongLong();
+ break;
+ case 0x1485c34: // /ALLOWBIND[:NO]
+ if(*(option+10) == ':' && (*(option+11) == 'n' || *(option+11) == 'N'))
+ PreventDllBinding = _False;
+ else
+ PreventDllBinding = _True;
+ break;
+ case 0x312011e: // /ALLOWISOLATION[:NO]
+ if(*(option+15) == ':' && (*(option+16) == 'n' || *(option+16) == 'N'))
+ AllowIsolation = _False;
+ else
+ AllowIsolation = _True;
+ break;
+ case 0x679c075: // /ASSEMBLYMODULE:filename
+ AddModuleNamesToAssembly += option+15;
+ break;
+ case 0x75f35f7: // /ASSEMBLYDEBUG[:DISABLE]
+ if(*(option+14) == ':' && (*(option+15) == 'D'))
+ AssemblyDebug = _False;
+ else
+ AssemblyDebug = _True;
+ break;
+ case 0x43294a5: // /ASSEMBLYLINKRESOURCE:filename
+ AssemblyLinkResource += option+22;
+ break;
+ case 0x062d065: // /ASSEMBLYRESOURCE:filename
+ LinkToManagedResourceFile = option+18;
+ break;
+ case 0x0336675: // /BASE:{address | @filename,key}
+ // Do we need to do a manual lookup when '@filename,key'?
+ // Seems BaseAddress only can contain the location...
+ // We don't use it in Qt, so keep it simple for now
+ BaseAddress = option+6;
+ break;
+ case 0x63bf065: // /CLRIMAGETYPE:{IJW|PURE|SAFE}
+ if(*(option+14) == 'I')
+ CLRImageType = "ForceIJWImage";
+ else if(*(option+14) == 'P')
+ CLRImageType = "ForcePureILImage";
+ else if(*(option+14) == 'S')
+ CLRImageType = "ForceSafeILImage";
+ break;
+ case 0x5f2a6a2: // /CLRSUPPORTLASTERROR{:NO | SYSTEMDLL}
+ if(*(option+20) == ':') {
+ if(*(option+21) == 'N') {
+ CLRSupportLastError = "Disabled";
+ } else if(*(option+21) == 'S') {
+ CLRSupportLastError = "SystemDlls";
+ }
+ } else {
+ CLRSupportLastError = "Enabled";
+ }
+ break;
+ case 0xc7984f5: // /CLRTHREADATTRIBUTE:{STA|MTA|NONE}
+ if(*(option+20) == 'N')
+ CLRThreadAttribute = "DefaultThreadingAttribute";
+ else if(*(option+20) == 'M')
+ CLRThreadAttribute = "MTAThreadingAttribute";
+ else if(*(option+20) == 'S')
+ CLRThreadAttribute = "STAThreadingAttribute";
+ break;
+ case 0xa8c637b: // /CLRUNMANAGEDCODECHECK[:NO]
+ if(*(option+23) == 'N')
+ CLRUnmanagedCodeCheck = _False;
+ else
+ CLRUnmanagedCodeCheck = _True;
+ break;
+ case 0x62d9e94: // /MANIFEST[:NO]
+ if ((*(option+9) == ':' && (*(option+10) == 'N' || *(option+10) == 'n')))
+ GenerateManifest = _False;
+ else
+ GenerateManifest = _True;
+ break;
+ case 0x8b64559: // /MANIFESTDEPENDENCY:manifest_dependency
+ AdditionalManifestDependencies += option+20;
+ break;
+ case 0xe9e8195: // /MANIFESTFILE:filename
+ ManifestFile = option+14;
+ break;
+ case 0x9e9fb83: // /MANIFESTUAC http://msdn.microsoft.com/en-us/library/bb384691%28VS.100%29.aspx
+ if ((*(option+12) == ':' && (*(option+13) == 'N' || *(option+13) == 'n')))
+ EnableUAC = _False;
+ else if((*(option+12) == ':' && (*(option+13) == 'l' || *(option+14) == 'e'))) { // level
+ if(*(option+20) == 'a')
+ UACExecutionLevel = "AsInvoker";
+ else if(*(option+20) == 'h')
+ UACExecutionLevel = "HighestAvailable";
+ else if(*(option+20) == 'r')
+ UACExecutionLevel = "RequireAdministrator";
+ } else if((*(option+12) == ':' && (*(option+13) == 'u' || *(option+14) == 'i'))) { // uiAccess
+ if(*(option+22) == 't')
+ UACUIAccess = _True;
+ else
+ UACUIAccess = _False;
+ } else if((*(option+12) == ':' && (*(option+13) == 'f' || *(option+14) == 'r'))) { // fragment
+ AdditionalOptions += option;
+ }else
+ EnableUAC = _True;
+ break;
+ case 0x3389797: // /DEBUG
+ GenerateDebugInformation = _True;
+ break;
+ case 0x0033896: // /DEF:filename
+ ModuleDefinitionFile = option+5;
+ break;
+ case 0x338a069: // /DELAY:{UNLOAD | NOBIND}
+ // MS documentation does not specify what to do with
+ // this option, so we'll put it in AdditionalOptions
+ AdditionalOptions += option;
+ break;
+ case 0x06f4bf4: // /DELAYLOAD:dllname
+ DelayLoadDLLs += option+11;
+ break;
+ case 0x06d451e: // /DELAYSIGN[:NO]
+ if(*(option+10) == ':' && (*(option+11) == 'n' || *(option+11) == 'N'))
+ DelaySign = _False;
+ else
+ DelaySign = _True;
+ break;
+ case 0x003390c: // /DLL
+ // This option is not used for vcproj files
+ break;
+ case 0x2ee8415: // /DYNAMICBASE[:NO]
+ if(*(option+12) == ':' && (*(option+13) == 'n' || *(option+13) == 'N'))
+ RandomizedBaseAddress = _False;
+ else
+ RandomizedBaseAddress = _True;
+ break;
+ case 0x33a3979: // /ENTRY:function
+ EntryPointSymbol = option+7;
+ break;
+ case 0x4504334: // /ERRORREPORT:[ NONE | PROMPT | QUEUE | SEND ]
+ if(*(option+12) == ':' ) {
+ if(*(option+13) == 'N')
+ LinkErrorReporting = "NoErrorReport";
+ else if(*(option+13) == 'P')
+ LinkErrorReporting = "PromptImmediately";
+ else if(*(option+13) == 'Q')
+ LinkErrorReporting = "QueueForNextLogin";
+ else if(*(option+13) == 'S')
+ LinkErrorReporting = "SendErrorReport";
+ }
+ break;
+ case 0x033c960: // /HEAP:reserve[,commit]
+ {
+ QStringList both = QString(option+6).split(",");
+ HeapReserveSize = both[0].toLongLong();
+ if(both.count() == 2)
+ HeapCommitSize = both[1].toLongLong();
+ }
+ break;
+ case 0x3d91494: // /IDLOUT:[path\]filename
+ MergedIDLBaseFileName = option+8;
+ break;
+ case 0x345a04c: // /IGNOREIDL
+ IgnoreEmbeddedIDL = _True;
+ break;
+ case 0x3e250e2: // /IMPLIB:filename
+ ImportLibrary = option+8;
+ break;
+ case 0xe281ab5: // /INCLUDE:symbol
+ ForceSymbolReferences += option+9;
+ break;
+ case 0xb28103c: // /INCREMENTAL[:no]
+ if(*(option+12) == ':' &&
+ (*(option+13) == 'n' || *(option+13) == 'N'))
+ LinkIncremental = linkIncrementalNo;
+ else
+ LinkIncremental = linkIncrementalYes;
+ break;
+ case 0x07f1ab2: // /KEYCONTAINER:name
+ KeyContainer = option+14;
+ break;
+ case 0xfadaf35: // /KEYFILE:filename
+ KeyFile = option+9;
+ break;
+ case 0x26e4675: // /LARGEADDRESSAWARE[:no]
+ if(*(option+18) == ':' &&
+ *(option+19) == 'n')
+ LargeAddressAware = addrAwareNoLarge;
+ else
+ LargeAddressAware = addrAwareLarge;
+ break;
+ case 0x2f96bc8: // /libpath:dir
+ case 0x0d745c8: // /LIBPATH:dir
+ AdditionalLibraryDirectories += option+9;
+ break;
+ case 0x0341877: // /LTCG[:NOSTATUS|:STATUS]
+ config->WholeProgramOptimization = _True;
+ if (config->CompilerVersion >= NET2005) {
+ LinkTimeCodeGeneration = optLTCGEnabled;
+ if(*(option+5) == ':') {
+ const char* str = option+6;
+ if (*str == 'S')
+ ShowProgress = linkProgressAll;
+#ifndef Q_OS_WIN
+ else if (strncasecmp(str, "pginstrument", 12))
+ LinkTimeCodeGeneration = optLTCGInstrument;
+ else if (strncasecmp(str, "pgoptimize", 10))
+ LinkTimeCodeGeneration = optLTCGOptimize;
+ else if (strncasecmp(str, "pgupdate", 8 ))
+ LinkTimeCodeGeneration = optLTCGUpdate;
+#else
+ else if (_stricmp(str, "pginstrument"))
+ LinkTimeCodeGeneration = optLTCGInstrument;
+ else if (_stricmp(str, "pgoptimize"))
+ LinkTimeCodeGeneration = optLTCGOptimize;
+ else if (_stricmp(str, "pgupdate"))
+ LinkTimeCodeGeneration = optLTCGUpdate;
+#endif
+ }
+ } else {
+ AdditionalOptions.append(option);
+ }
+ break;
+ case 0x379ED25:
+ case 0x157cf65: // /MACHINE:{AM33|ARM|CEE|IA64|X86|M32R|MIPS|MIPS16|MIPSFPU|MIPSFPU16|MIPSR41XX|PPC|SH3|SH4|SH5|THUMB|TRICORE}
+ switch (elfHash(option+9)) {
+ // Very limited documentation on all options but X86,
+ case 0x0005bb6: // X86
+ TargetMachine = machineX86;
+ break;
+ case 0x0005b94: // X64
+ TargetMachine = machineX64;
+ break;
+ // so we put the others in AdditionalOptions...
+ case 0x0046063: // AM33
+ case 0x000466d: // ARM
+ case 0x0004795: // CEE
+ case 0x0004963: // EBC
+ case 0x004d494: // IA64
+ case 0x0050672: // M32R
+ case 0x0051e53: // MIPS
+ case 0x51e5646: // MIPS16
+ case 0x1e57b05: // MIPSFPU
+ case 0x57b09a6: // MIPSFPU16
+ case 0x5852738: // MIPSR41XX
+ case 0x0005543: // PPC
+ case 0x00057b3: // SH3
+ case 0x57b7980: // SH3DSP
+ case 0x00057b4: // SH4
+ case 0x00057b5: // SH5
+ case 0x058da12: // THUMB
+ case 0x96d8435: // TRICORE
+ default:
+ AdditionalOptions += option;
+ break;
+ }
+ break;
+ case 0x0034160: // /MAP[:filename]
+ GenerateMapFile = _True;
+ if (option[4] == ':')
+ MapFileName = option+5;
+ break;
+ case 0x164e1ef: // /MAPINFO:{EXPORTS|LINES}
+ if(*(option+9) == 'E')
+ MapExports = _True;
+ else if(*(option+9) == 'L')
+ MapLines = _True;
+ break;
+ case 0x341a6b5: // /MERGE:from=to
+ MergeSections = option+7;
+ break;
+ case 0x0341d8c: // /MIDL:@file
+ MidlCommandFile = option+7;
+ break;
+ case 0x84e2679: // /NOASSEMBLY
+ TurnOffAssemblyGeneration = _True;
+ break;
+ case 0x2b21942: // /NODEFAULTLIB[:library]
+ if(*(option+13) == '\0')
+ IgnoreAllDefaultLibraries = _True;
+ else
+ IgnoreDefaultLibraryNames += option+14;
+ break;
+ case 0x33a3a39: // /NOENTRY
+ ResourceOnlyDLL = _True;
+ break;
+ case 0x434138f: // /NOLOGO
+ SuppressStartupBanner = _True;
+ break;
+ case 0xc841054: // /NXCOMPAT[:NO]
+ if ((*(option+9) == ':' && (*(option+10) == 'N' || *(option+10) == 'n')))
+ DataExecutionPrevention = _False;
+ else
+ DataExecutionPrevention = _True;
+ break;
+ case 0x0034454: // /OPT:{REF | NOREF | ICF[=iterations] | NOICF | WIN98 | NOWIN98}
+ {
+ char third = *(option+7);
+ switch (third) {
+ case 'F': // REF
+ if(*(option+5) == 'R') {
+ OptimizeReferences = optReferences;
+ } else { // ICF[=iterations]
+ EnableCOMDATFolding = optFolding;
+ // [=iterations] case is not documented
+ }
+ break;
+ case 'R': // NOREF
+ OptimizeReferences = optNoReferences;
+ break;
+ case 'I': // NOICF
+ EnableCOMDATFolding = optNoFolding;
+ break;
+ case 'N': // WIN98
+ OptimizeForWindows98 = optWin98Yes;
+ break;
+ case 'W': // NOWIN98
+ OptimizeForWindows98 = optWin98No;
+ break;
+ default:
+ found = false;
+ }
+ }
+ break;
+ case 0x34468a2: // /ORDER:@filename
+ FunctionOrder = option+8;
+ break;
+ case 0x00344a4: // /OUT:filename
+ OutputFile = option+5;
+ break;
+ case 0x0034482: // /PDB:filename
+ ProgramDatabaseFile = option+5;
+ break;
+ case 0xa2ad314: // /PDBSTRIPPED:pdb_file_name
+ StripPrivateSymbols = option+13;
+ break;
+ case 0x6a09535: // /RELEASE
+ SetChecksum = _True;
+ break;
+ case 0x348857b: // /STACK:reserve[,commit]
+ {
+ QStringList both = QString(option+7).split(",");
+ StackReserveSize = both[0].toLongLong();
+ if(both.count() == 2)
+ StackCommitSize = both[1].toLongLong();
+ }
+ break;
+ case 0x75AA4D8: // /SAFESH:{NO}
+ {
+ AdditionalOptions += option;
+ break;
+ }
+ case 0x9B3C00D:
+ case 0x78dc00d: // /SUBSYSTEM:{CONSOLE|EFI_APPLICATION|EFI_BOOT_SERVICE_DRIVER|EFI_ROM|EFI_RUNTIME_DRIVER|NATIVE|POSIX|WINDOWS|WINDOWSCE}[,major[.minor]]
+ {
+ // Split up in subsystem, and version number
+ QStringList both = QString(option+11).split(",");
+ switch (elfHash(both[0].toLatin1())) {
+ case 0x8438445: // CONSOLE
+ SubSystem = subSystemConsole;
+ break;
+ case 0xbe29493: // WINDOWS
+ SubSystem = subSystemWindows;
+ break;
+ // The following are undocumented, so add them to AdditionalOptions
+ case 0x240949e: // EFI_APPLICATION
+ case 0xe617652: // EFI_BOOT_SERVICE_DRIVER
+ case 0x9af477d: // EFI_ROM
+ case 0xd34df42: // EFI_RUNTIME_DRIVER
+ case 0x5268ea5: // NATIVE
+ case 0x05547e8: // POSIX
+ case 0x2949c95: // WINDOWSCE
+ case 0x4B69795: // windowsce
+ AdditionalOptions += option;
+ break;
+ default:
+ found = false;
+ }
+ }
+ break;
+ case 0x8b654de: // /SWAPRUN:{NET | CD}
+ if(*(option+9) == 'N')
+ SwapRunFromNet = _True;
+ else if(*(option+9) == 'C')
+ SwapRunFromCD = _True;
+ else
+ found = false;
+ break;
+ case 0x34906d4: // /TLBID:id
+ TypeLibraryResourceID = QString(option+7).toLongLong();
+ break;
+ case 0x4907494: // /TLBOUT:[path\]filename
+ TypeLibraryFile = option+8;
+ break;
+ case 0x976b525: // /TSAWARE[:NO]
+ if(*(option+8) == ':')
+ TerminalServerAware = termSvrAwareNo;
+ else
+ TerminalServerAware = termSvrAwareYes;
+ break;
+ case 0xaa67735: // /VERBOSE[:lib]
+ if(*(option+9) == ':') {
+ ShowProgress = linkProgressLibs;
+ AdditionalOptions += option;
+ } else {
+ ShowProgress = linkProgressAll;
+ }
+ break;
+ case 0xaa77f7e: // /VERSION:major[.minor]
+ Version = option+9;
+ break;
+ case 0x0034c50: // /WS[:NO]
+ if (config->CompilerVersion >= NET2010) {
+ if(*(option+3) == ':')
+ TreatWarningsAsErrors = _False;
+ else
+ TreatWarningsAsErrors = _True;
+ } else {
+ AdditionalOptions += option;
+ }
+ break;
+ default:
+ AdditionalOptions += option;
+ break;
+ }
+ if(!found) {
+ warn_msg(WarnLogic, "Could not parse Linker options: %s, added as AdditionalOption", option);
+ AdditionalOptions += option;
+ }
+ return found;
+}
+
+// VCMIDLTool -------------------------------------------------------
+VCMIDLTool::VCMIDLTool()
+ : DefaultCharType(midlCharUnsigned),
+ EnableErrorChecks(midlDisableAll),
+ ErrorCheckAllocations(unset),
+ ErrorCheckBounds(unset),
+ ErrorCheckEnumRange(unset),
+ ErrorCheckRefPointers(unset),
+ ErrorCheckStubData(unset),
+ GenerateStublessProxies(unset),
+ GenerateTypeLibrary(unset),
+ IgnoreStandardIncludePath(unset),
+ MkTypLibCompatible(unset),
+ StructMemberAlignment(midlAlignNotSet),
+ SuppressStartupBanner(unset),
+ TargetEnvironment(midlTargetNotSet),
+ ValidateParameters(unset),
+ WarnAsError(unset),
+ WarningLevel(midlWarningLevel_0),
+ ApplicationConfigurationMode(unset),
+ ValidateAllParameters(unset),
+ SuppressCompilerWarnings(unset),
+ LocaleID(-1)
+{
+}
+
+bool VCMIDLTool::parseOption(const char* option)
+{
+#ifdef USE_DISPLAY_HASH
+ displayHash("/D name[=def]"); displayHash("/I directory-list"); displayHash("/Oi");
+ displayHash("/Oic"); displayHash("/Oicf"); displayHash("/Oif"); displayHash("/Os");
+ displayHash("/U name"); displayHash("/WX"); displayHash("/W{0|1|2|3|4}");
+ displayHash("/Zp {N}"); displayHash("/Zs"); displayHash("/acf filename");
+ displayHash("/align {N}"); displayHash("/app_config"); displayHash("/c_ext");
+ displayHash("/char ascii7"); displayHash("/char signed"); displayHash("/char unsigned");
+ displayHash("/client none"); displayHash("/client stub"); displayHash("/confirm");
+ displayHash("/cpp_cmd cmd_line"); displayHash("/cpp_opt options");
+ displayHash("/cstub filename"); displayHash("/dlldata filename"); displayHash("/env win32");
+ displayHash("/env win64"); displayHash("/error all"); displayHash("/error allocation");
+ displayHash("/error bounds_check"); displayHash("/error enum"); displayHash("/error none");
+ displayHash("/error ref"); displayHash("/error stub_data"); displayHash("/h filename");
+ displayHash("/header filename"); displayHash("/iid filename"); displayHash("/lcid");
+ displayHash("/mktyplib203"); displayHash("/ms_ext"); displayHash("/ms_union");
+ displayHash("/msc_ver <nnnn>"); displayHash("/newtlb"); displayHash("/no_cpp");
+ displayHash("/no_def_idir"); displayHash("/no_default_epv"); displayHash("/no_format_opt");
+ displayHash("/no_warn"); displayHash("/nocpp"); displayHash("/nologo"); displayHash("/notlb");
+ displayHash("/o filename"); displayHash("/oldnames"); displayHash("/oldtlb");
+ displayHash("/osf"); displayHash("/out directory"); displayHash("/pack {N}");
+ displayHash("/prefix all"); displayHash("/prefix client"); displayHash("/prefix server");
+ displayHash("/prefix switch"); displayHash("/protocol all"); displayHash("/protocol dce");
+ displayHash("/protocol ndr64"); displayHash("/proxy filename"); displayHash("/robust");
+ displayHash("/rpcss"); displayHash("/savePP"); displayHash("/server none");
+ displayHash("/server stub"); displayHash("/sstub filename"); displayHash("/syntax_check");
+ displayHash("/target {system}"); displayHash("/tlb filename"); displayHash("/use_epv");
+ displayHash("/win32"); displayHash("/win64");
+#endif
+ bool found = true;
+ int offset = 0;
+
+ const uint optionHash = elfHash(option);
+
+ if (config->CompilerVersion < NET2010) {
+ switch (optionHash) {
+ case 0x5b1cb97: // /app_config
+ case 0x5a2fc64: // /client {none|stub}
+ case 0x35aabb2: // /cstub filename
+ case 0x64ceb12: // /newtlb
+ case 0x556dbee: // /no_warn
+ case 0x662bb12: // /oldtlb
+ case 0x69c9cf2: // /server {none|stub}
+ case 0x36aabb2: // /sstub filename
+ AdditionalOptions += option;
+ return true;
+ }
+ }
+
+ switch(optionHash) {
+ case 0x0000334: // /D name[=def]
+ PreprocessorDefinitions += option+3;
+ break;
+ case 0x0000339: // /I directory-list
+ AdditionalIncludeDirectories += option+3;
+ break;
+ case 0x0345f96: // /Oicf
+ case 0x00345f6: // /Oif
+ GenerateStublessProxies = _True;
+ break;
+ case 0x0000345: // /U name
+ UndefinePreprocessorDefinitions += option+3;
+ break;
+ case 0x00034c8: // /WX
+ WarnAsError = _True;
+ break;
+ case 0x3582fde: // /align {N}
+ offset = 3; // Fallthrough
+ case 0x0003510: // /Zp {N}
+ switch (*(option+offset+4)) {
+ case '1':
+ StructMemberAlignment = (*(option+offset+5) == '\0') ? midlAlignSingleByte : midlAlignSixteenBytes;
+ break;
+ case '2':
+ StructMemberAlignment = midlAlignTwoBytes;
+ break;
+ case '4':
+ StructMemberAlignment = midlAlignFourBytes;
+ break;
+ case '8':
+ StructMemberAlignment = midlAlignEightBytes;
+ break;
+ default:
+ found = false;
+ }
+ break;
+ case 0x5b1cb97: // /app_config
+ ApplicationConfigurationMode = _True;
+ break;
+ case 0x0359e82: // /char {ascii7|signed|unsigned}
+ switch(*(option+6)) {
+ case 'a':
+ DefaultCharType = midlCharAscii7;
+ break;
+ case 's':
+ DefaultCharType = midlCharSigned;
+ break;
+ case 'u':
+ DefaultCharType = midlCharUnsigned;
+ break;
+ default:
+ found = false;
+ }
+ break;
+ case 0x5a2fc64: // /client {none|stub}
+ if(*(option+8) == 's')
+ GenerateClientFiles = "Stub";
+ else
+ GenerateClientFiles = "None";
+ break;
+ case 0xa766524: // /cpp_opt options
+ CPreprocessOptions += option+9;
+ break;
+ case 0x35aabb2: // /cstub filename
+ ClientStubFile = option+7;
+ break;
+ case 0xb32abf1: // /dlldata filename
+ DLLDataFileName = option + 9;
+ break;
+ case 0x0035c56: // /env {win32|win64}
+ TargetEnvironment = (*(option+8) == '6') ? midlTargetWin64 : midlTargetWin32;
+ break;
+ case 0x35c9962: // /error {all|allocation|bounds_check|enum|none|ref|stub_data}
+ EnableErrorChecks = midlEnableCustom;
+ switch (*(option+7)) {
+ case 'a':
+ if(*(option+10) == '\0')
+ EnableErrorChecks = midlEnableAll;
+ else
+ ErrorCheckAllocations = _True;
+ break;
+ case 'b':
+ ErrorCheckBounds = _True;
+ break;
+ case 'e':
+ ErrorCheckEnumRange = _True;
+ break;
+ case 'n':
+ EnableErrorChecks = midlDisableAll;
+ break;
+ case 'r':
+ ErrorCheckRefPointers = _True;
+ break;
+ case 's':
+ ErrorCheckStubData = _True;
+ break;
+ default:
+ found = false;
+ }
+ break;
+ case 0x5eb7af2: // /header filename
+ offset = 5;
+ case 0x0000358: // /h filename
+ HeaderFileName = option + offset + 3;
+ break;
+ case 0x0035ff4: // /iid filename
+ InterfaceIdentifierFileName = option+5;
+ break;
+ case 0x64b7933: // /mktyplib203
+ MkTypLibCompatible = _True;
+ break;
+ case 0x64ceb12: // /newtlb
+ TypeLibFormat = "NewFormat";
+ break;
+ case 0x8e0b0a2: // /no_def_idir
+ IgnoreStandardIncludePath = _True;
+ break;
+ case 0x65635ef: // /nologo
+ SuppressStartupBanner = _True;
+ break;
+ case 0x695e9f4: // /no_robust
+ ValidateAllParameters = _False;
+ break;
+ case 0x3656b22: // /notlb
+ GenerateTypeLibrary = _True;
+ break;
+ case 0x556dbee: // /no_warn
+ SuppressCompilerWarnings = _True;
+ break;
+ case 0x000035f: // /o filename
+ RedirectOutputAndErrors = option+3;
+ break;
+ case 0x662bb12: // /oldtlb
+ TypeLibFormat = "OldFormat";
+ break;
+ case 0x00366c4: // /out directory
+ OutputDirectory = option+5;
+ break;
+ case 0x36796f9: // /proxy filename
+ ProxyFileName = option+7;
+ break;
+ case 0x6959c94: // /robust
+ ValidateParameters = _True;
+ break;
+ case 0x6a88df4: // /target {system}
+ if(*(option+11) == '6')
+ TargetEnvironment = midlTargetWin64;
+ else
+ TargetEnvironment = midlTargetWin32;
+ break;
+ case 0x69c9cf2: // /server {none|stub}
+ if(*(option+8) == 's')
+ GenerateServerFiles = "Stub";
+ else
+ GenerateServerFiles = "None";
+ break;
+ case 0x36aabb2: // /sstub filename
+ ServerStubFile = option+7;
+ break;
+ case 0x0036b22: // /tlb filename
+ TypeLibraryName = option+5;
+ break;
+ case 0x36e0162: // /win32
+ TargetEnvironment = midlTargetWin32;
+ break;
+ case 0x36e0194: // /win64
+ TargetEnvironment = midlTargetWin64;
+ break;
+ case 0x0003459: // /Oi
+ case 0x00345f3: // /Oic
+ case 0x0003463: // /Os
+ case 0x0003513: // /Zs
+ case 0x0035796: // /acf filename
+ case 0x3595cf4: // /c_ext
+ case 0xa64d3dd: // /confirm
+ case 0xa765b64: // /cpp_cmd cmd_line
+ case 0x03629f4: // /lcid
+ case 0x6495cc4: // /ms_ext
+ case 0x96c7a1e: // /ms_union
+ case 0x4996fa2: // /msc_ver <nnnn>
+ case 0x6555a40: // /no_cpp
+ case 0xf64d6a6: // /no_default_epv
+ case 0x6dd9384: // /no_format_opt
+ case 0x3655a70: // /nocpp
+ case 0x2b455a3: // /oldnames
+ case 0x0036696: // /osf
+ case 0x036679b: // /pack {N}
+ case 0x678bd38: // /prefix {all|client|server|switch}
+ case 0x96b702c: // /protocol {all|dce|ndr64}
+ case 0x3696aa3: // /rpcss
+ case 0x698ca60: // /savePP
+ case 0xce9b12b: // /syntax_check
+ case 0xc9b5f16: // /use_epv
+ AdditionalOptions += option;
+ break;
+ default:
+ // /W{0|1|2|3|4} case
+ if(*(option+1) == 'W') {
+ switch (*(option+2)) {
+ case '0':
+ WarningLevel = midlWarningLevel_0;
+ break;
+ case '1':
+ WarningLevel = midlWarningLevel_1;
+ break;
+ case '2':
+ WarningLevel = midlWarningLevel_2;
+ break;
+ case '3':
+ WarningLevel = midlWarningLevel_3;
+ break;
+ case '4':
+ WarningLevel = midlWarningLevel_4;
+ break;
+ default:
+ found = false;
+ }
+ }
+ break;
+ }
+ if(!found)
+ warn_msg(WarnLogic, "Could not parse MIDL option: %s", option);
+ return true;
+}
+
+// VCLibrarianTool --------------------------------------------------
+VCLibrarianTool::VCLibrarianTool()
+ : IgnoreAllDefaultLibraries(unset),
+ SuppressStartupBanner(_True)
+{
+}
+
+// VCCustomBuildTool ------------------------------------------------
+VCCustomBuildTool::VCCustomBuildTool()
+{
+ ToolName = "VCCustomBuildTool";
+}
+
+// VCResourceCompilerTool -------------------------------------------
+VCResourceCompilerTool::VCResourceCompilerTool()
+ : Culture(rcUseDefault),
+ IgnoreStandardIncludePath(unset),
+ ShowProgress(linkProgressNotSet),
+ SuppressStartupBanner(unset)
+{
+ PreprocessorDefinitions = QStringList("NDEBUG");
+}
+
+// VCDeploymentTool --------------------------------------------
+VCDeploymentTool::VCDeploymentTool()
+ : RegisterOutput(registerNo)
+{
+ DeploymentTag = "DeploymentTool";
+ RemoteDirectory = "";
+}
+
+VCEventTool::VCEventTool(const QString &eventName)
+ : ExcludedFromBuild(unset)
+{
+ EventName = eventName;
+ ToolName = "VC";
+ ToolName += eventName;
+ ToolName += "Tool";
+}
+
+// VCPostBuildEventTool ---------------------------------------------
+VCPostBuildEventTool::VCPostBuildEventTool()
+ : VCEventTool("PostBuildEvent")
+{
+}
+
+// VCPreBuildEventTool ----------------------------------------------
+VCPreBuildEventTool::VCPreBuildEventTool()
+ : VCEventTool("PreBuildEvent")
+{
+}
+
+// VCPreLinkEventTool -----------------------------------------------
+VCPreLinkEventTool::VCPreLinkEventTool()
+ : VCEventTool("PreLinkEvent")
+{
+}
+
+// VCConfiguration --------------------------------------------------
+
+VCConfiguration::VCConfiguration()
+ : ATLMinimizesCRunTimeLibraryUsage(unset),
+ BuildBrowserInformation(unset),
+ CharacterSet(charSetNotSet),
+ ConfigurationType(typeApplication),
+ RegisterOutput(unset),
+ UseOfATL(useATLNotSet),
+ UseOfMfc(useMfcStdWin),
+ WholeProgramOptimization(unset)
+{
+ compiler.config = this;
+ linker.config = this;
+ idl.config = this;
+ custom.config = this;
+}
+
+// VCFilter ---------------------------------------------------------
+VCFilter::VCFilter()
+ : ParseFiles(unset),
+ Config(0)
+{
+ useCustomBuildTool = false;
+ useCompilerTool = false;
+}
+
+void VCFilter::addFile(const QString& filename)
+{
+ Files += VCFilterFile(filename);
+}
+
+void VCFilter::addFile(const VCFilterFile& fileInfo)
+{
+ Files += VCFilterFile(fileInfo);
+}
+
+void VCFilter::addFiles(const QStringList& fileList)
+{
+ for (int i = 0; i < fileList.count(); ++i)
+ addFile(fileList.at(i));
+}
+
+void VCFilter::modifyPCHstage(QString str)
+{
+ bool autogenSourceFile = Project->autogenPrecompCPP;
+ bool pchThroughSourceFile = !Project->precompCPP.isEmpty();
+ bool isCFile = false;
+ for (QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
+ if (str.endsWith(*it)) {
+ isCFile = true;
+ break;
+ }
+ }
+ bool isHFile = Option::hasFileExtension(str, Option::h_ext) && (str == Project->precompH);
+ bool isCPPFile = pchThroughSourceFile && (str == Project->precompCPP);
+
+ if(!isCFile && !isHFile && !isCPPFile)
+ return;
+
+ if(isHFile && pchThroughSourceFile) {
+ if (autogenSourceFile) {
+ useCustomBuildTool = true;
+ QString toFile(Project->precompCPP);
+ CustomBuildTool.Description = "Generating precompiled header source file '" + toFile + "' ...";
+ CustomBuildTool.Outputs += toFile;
+
+ QStringList lines;
+ CustomBuildTool.CommandLine +=
+ "echo /*-------------------------------------------------------------------- >" + toFile;
+ lines << "* Precompiled header source file used by Visual Studio.NET to generate";
+ lines << "* the .pch file.";
+ lines << "*";
+ lines << "* Due to issues with the dependencies checker within the IDE, it";
+ lines << "* sometimes fails to recompile the PCH file, if we force the IDE to";
+ lines << "* create the PCH file directly from the header file.";
+ lines << "*";
+ lines << "* This file is auto-generated by qmake since no PRECOMPILED_SOURCE was";
+ lines << "* specified, and is used as the common stdafx.cpp. The file is only";
+ lines << QLatin1String("* generated when creating ")
+ + (Config->CompilerVersion < NET2010 ? ".vcproj" : ".vcxproj")
+ + " project files, and is not used for";
+ lines << "* command line compilations by nmake.";
+ lines << "*";
+ lines << "* WARNING: All changes made in this file will be lost.";
+ lines << "--------------------------------------------------------------------*/";
+ lines << "#include \"" + Project->precompHFilename + "\"";
+ foreach(QString line, lines)
+ CustomBuildTool.CommandLine += "echo " + line + ">>" + toFile;
+ }
+ return;
+ }
+
+ useCompilerTool = true;
+ // Setup PCH options
+ CompilerTool.UsePrecompiledHeader = (isCFile ? pchNone : pchCreateUsingSpecific);
+ CompilerTool.PrecompiledHeaderThrough = (isCPPFile ? Project->precompHFilename : QString("$(NOINHERIT)"));
+ CompilerTool.ForcedIncludeFiles = QStringList("$(NOINHERIT)");
+}
+
+bool VCFilter::addExtraCompiler(const VCFilterFile &info)
+{
+ const QStringList &extraCompilers = Project->extraCompilerSources.value(info.file);
+ if (extraCompilers.isEmpty())
+ return false;
+
+ QString inFile = info.file;
+
+ // is the extracompiler rule on a file with a built in compiler?
+ const QStringList &objectMappedFile = Project->extraCompilerOutputs[inFile];
+ bool hasBuiltIn = false;
+ if (!objectMappedFile.isEmpty()) {
+ hasBuiltIn = Project->hasBuiltinCompiler(objectMappedFile.at(0));
+// qDebug("*** Extra compiler file has object mapped file '%s' => '%s'", qPrintable(inFile), qPrintable(objectMappedFile.join(" ")));
+ }
+
+ CustomBuildTool.AdditionalDependencies.clear();
+ CustomBuildTool.CommandLine.clear();
+ CustomBuildTool.Description.clear();
+ CustomBuildTool.Outputs.clear();
+ CustomBuildTool.ToolPath.clear();
+ CustomBuildTool.ToolName = QLatin1String(_VCCustomBuildTool);
+
+ for (int x = 0; x < extraCompilers.count(); ++x) {
+ const QString &extraCompilerName = extraCompilers.at(x);
+
+ if (!Project->verifyExtraCompiler(extraCompilerName, inFile) && !hasBuiltIn)
+ continue;
+
+ // All information about the extra compiler
+ QString tmp_out = Project->project->first(extraCompilerName + ".output");
+ QString tmp_cmd = Project->project->variables()[extraCompilerName + ".commands"].join(" ");
+ QString tmp_cmd_name = Project->project->variables()[extraCompilerName + ".name"].join(" ");
+ QStringList tmp_dep = Project->project->variables()[extraCompilerName + ".depends"];
+ QString tmp_dep_cmd = Project->project->variables()[extraCompilerName + ".depend_command"].join(" ");
+ QStringList vars = Project->project->variables()[extraCompilerName + ".variables"];
+ QStringList configs = Project->project->variables()[extraCompilerName + ".CONFIG"];
+ bool combined = configs.indexOf("combine") != -1;
+
+ QString cmd, cmd_name, out;
+ QStringList deps, inputs;
+ // Variabel replacement of output name
+ out = Option::fixPathToTargetOS(
+ Project->replaceExtraCompilerVariables(tmp_out, inFile, QString()),
+ false);
+
+ // If file has built-in compiler, we've swapped the input and output of
+ // the command, as we in Visual Studio cannot have a Custom Buildstep on
+ // a file which uses a built-in compiler. We would in this case only get
+ // the result from the extra compiler. If 'hasBuiltIn' is true, we know
+ // that we're actually on the _output_file_ of the result, and we
+ // therefore swap inFile and out below, since the extra-compiler still
+ // must see it as the original way. If the result also has a built-in
+ // compiler, too bad..
+ if (hasBuiltIn) {
+ out = inFile;
+ inFile = objectMappedFile.at(0);
+ }
+
+ // Dependency for the output
+ if(!tmp_dep.isEmpty())
+ deps = tmp_dep;
+ if(!tmp_dep_cmd.isEmpty()) {
+ // Execute dependency command, and add every line as a dep
+ char buff[256];
+ QString dep_cmd = Project->replaceExtraCompilerVariables(tmp_dep_cmd,
+ Option::fixPathToLocalOS(inFile, true, false),
+ out);
+ if(Project->canExecute(dep_cmd)) {
+ dep_cmd.prepend(QLatin1String("cd ")
+ + Project->escapeFilePath(Option::fixPathToLocalOS(Option::output_dir, false))
+ + QLatin1String(" && "));
+ 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 extradeps = indeps.split(QLatin1Char('\n'));
+ for (int i = 0; i < extradeps.count(); ++i) {
+ QString dd = extradeps.at(i).simplified();
+ if (!dd.isEmpty())
+ deps += Project->fileFixify(dd, QString(), Option::output_dir);
+ }
+ }
+ }
+ }
+ }
+ for (int i = 0; i < deps.count(); ++i)
+ deps[i] = Option::fixPathToTargetOS(
+ Project->replaceExtraCompilerVariables(deps.at(i), inFile, out),
+ false).trimmed();
+ // Command for file
+ if (combined) {
+ // Add dependencies for each file
+ QStringList tmp_in = Project->project->variables()[extraCompilerName + ".input"];
+ for (int a = 0; a < tmp_in.count(); ++a) {
+ const QStringList &files = Project->project->variables()[tmp_in.at(a)];
+ for (int b = 0; b < files.count(); ++b) {
+ deps += Project->findDependencies(files.at(b));
+ inputs += Option::fixPathToTargetOS(files.at(b), false);
+ }
+ }
+ deps += inputs; // input files themselves too..
+
+ // Replace variables for command w/all input files
+ // ### join gives path issues with directories containing spaces!
+ cmd = Project->replaceExtraCompilerVariables(tmp_cmd,
+ inputs.join(" "),
+ out);
+ } else {
+ deps += inFile; // input file itself too..
+ cmd = Project->replaceExtraCompilerVariables(tmp_cmd,
+ inFile,
+ out);
+ }
+ // Name for command
+ if(!tmp_cmd_name.isEmpty()) {
+ cmd_name = Project->replaceExtraCompilerVariables(tmp_cmd_name, inFile, out);
+ } else {
+ int space = cmd.indexOf(' ');
+ if(space != -1)
+ cmd_name = cmd.left(space);
+ else
+ cmd_name = cmd;
+ if((cmd_name[0] == '\'' || cmd_name[0] == '"') &&
+ cmd_name[0] == cmd_name[cmd_name.length()-1])
+ cmd_name = cmd_name.mid(1,cmd_name.length()-2);
+ }
+
+ // Fixify paths
+ for (int i = 0; i < deps.count(); ++i)
+ deps[i] = Option::fixPathToTargetOS(deps[i], false);
+
+
+ // Output in info.additionalFile -----------
+ if (!CustomBuildTool.Description.isEmpty())
+ CustomBuildTool.Description += ", ";
+ CustomBuildTool.Description += cmd_name;
+ CustomBuildTool.CommandLine += VCToolBase::fixCommandLine(cmd.trimmed());
+ int space = cmd.indexOf(' ');
+ QFileInfo finf(cmd.left(space));
+ if (CustomBuildTool.ToolPath.isEmpty())
+ CustomBuildTool.ToolPath += Option::fixPathToTargetOS(finf.path());
+ CustomBuildTool.Outputs += out;
+
+ deps += CustomBuildTool.AdditionalDependencies;
+ deps += cmd.left(cmd.indexOf(' '));
+ // Make sure that all deps are only once
+ QMap<QString, bool> uniqDeps;
+ for (int c = 0; c < deps.count(); ++c) {
+ QString aDep = deps.at(c).trimmed();
+ if (!aDep.isEmpty())
+ uniqDeps[aDep] = false;
+ }
+ CustomBuildTool.AdditionalDependencies = uniqDeps.keys();
+ }
+
+ // Ensure that none of the output files are also dependencies. Or else, the custom buildstep
+ // will be rebuild every time, even if nothing has changed.
+ foreach(QString output, CustomBuildTool.Outputs) {
+ CustomBuildTool.AdditionalDependencies.removeAll(output);
+ }
+
+ useCustomBuildTool = !CustomBuildTool.CommandLine.isEmpty();
+ return useCustomBuildTool;
+}
+
+// VCProjectSingleConfig --------------------------------------------
+VCFilter& VCProjectSingleConfig::filterForExtraCompiler(const QString &compilerName)
+{
+ for (int i = 0; i < ExtraCompilersFiles.count(); ++i)
+ if (ExtraCompilersFiles.at(i).Name == compilerName)
+ return ExtraCompilersFiles[i];
+
+ static VCFilter nullFilter;
+ return nullFilter;
+}
+
+// Tree file generation ---------------------------------------------
+void TreeNode::generateXML(XmlOutput &xml, const QString &tagName, VCProject &tool, const QString &filter) {
+ if (children.size()) {
+ // Filter
+ ChildrenMap::ConstIterator it, end = children.constEnd();
+ if (!tagName.isEmpty()) {
+ xml << tag("Filter")
+ << attr("Name", tagName)
+ << attr("Filter", "");
+ }
+ // First round, do nested filters
+ for (it = children.constBegin(); it != end; ++it)
+ if ((*it)->children.size())
+ (*it)->generateXML(xml, it.key(), tool, filter);
+ // Second round, do leafs
+ for (it = children.constBegin(); it != end; ++it)
+ if (!(*it)->children.size())
+ (*it)->generateXML(xml, it.key(), tool, filter);
+
+ if (!tagName.isEmpty())
+ xml << closetag("Filter");
+ } else {
+ // Leaf
+ VCProjectWriter::outputFileConfigs(tool, xml, info, filter);
+ }
+}
+
+// Flat file generation ---------------------------------------------
+void FlatNode::generateXML(XmlOutput &xml, const QString &/*tagName*/, VCProject &tool, const QString &filter) {
+ if (children.size()) {
+ ChildrenMapFlat::ConstIterator it = children.constBegin();
+ ChildrenMapFlat::ConstIterator end = children.constEnd();
+ for (; it != end; ++it) {
+ VCProjectWriter::outputFileConfigs(tool, xml, (*it), filter);
+ }
+ }
+}
+
+void VCProjectWriter::write(XmlOutput &xml, VCProjectSingleConfig &tool)
+{
+ xml << decl("1.0", "Windows-1252")
+ << tag(_VisualStudioProject)
+ << attrS(_ProjectType, "Visual C++")
+ << attrS(_Version, tool.Version)
+ << attrS(_Name, tool.Name)
+ << attrS(_ProjectGUID, tool.ProjectGUID)
+ << attrS(_Keyword, tool.Keyword)
+ << attrS(_SccProjectName, tool.SccProjectName)
+ << attrS(_SccLocalPath, tool.SccLocalPath)
+ << tag(_Platforms)
+ << tag(_Platform)
+ << attrS(_Name, tool.PlatformName)
+ << closetag(_Platforms)
+ << tag(_Configurations);
+ write(xml, tool.Configuration);
+ xml << closetag(_Configurations)
+ << tag(q_Files);
+ // Add this configuration into a multi-config project, since that's where we have the flat/tree
+ // XML output functionality
+ VCProject tempProj;
+ tempProj.SingleProjects += tool;
+ outputFilter(tempProj, xml, "Sources");
+ outputFilter(tempProj, xml, "Headers");
+ outputFilter(tempProj, xml, "GeneratedFiles");
+ outputFilter(tempProj, xml, "LexYaccFiles");
+ outputFilter(tempProj, xml, "TranslationFiles");
+ outputFilter(tempProj, xml, "FormFiles");
+ outputFilter(tempProj, xml, "ResourceFiles");
+ for (int x = 0; x < tempProj.ExtraCompilers.count(); ++x) {
+ outputFilter(tempProj, xml, tempProj.ExtraCompilers.at(x));
+ }
+ outputFilter(tempProj, xml, "RootFiles");
+ xml << closetag(q_Files)
+ << tag(_Globals)
+ << data(); // No "/>" end tag
+}
+
+void VCProjectWriter::write(XmlOutput &xml, VCProject &tool)
+{
+ if (tool.SingleProjects.count() == 0) {
+ warn_msg(WarnLogic, "Generator: .NET: no single project in merge project, no output");
+ return;
+ }
+
+ xml << decl("1.0", "Windows-1252")
+ << tag(_VisualStudioProject)
+ << attrS(_ProjectType, "Visual C++")
+ << attrS(_Version, tool.Version)
+ << attrS(_Name, tool.Name)
+ << attrS(_ProjectGUID, tool.ProjectGUID)
+ << attrS(_Keyword, tool.Keyword)
+ << attrS(_SccProjectName, tool.SccProjectName)
+ << attrS(_SccLocalPath, tool.SccLocalPath)
+ << tag(_Platforms)
+ << tag(_Platform)
+ << attrS(_Name, tool.PlatformName)
+ << closetag(_Platforms)
+ << tag(_Configurations);
+ // Output each configuration
+ for (int i = 0; i < tool.SingleProjects.count(); ++i)
+ write(xml, tool.SingleProjects.at(i).Configuration);
+ xml << closetag(_Configurations)
+ << tag(q_Files);
+ outputFilter(tool, xml, "Sources");
+ outputFilter(tool, xml, "Headers");
+ outputFilter(tool, xml, "GeneratedFiles");
+ outputFilter(tool, xml, "LexYaccFiles");
+ outputFilter(tool, xml, "TranslationFiles");
+ outputFilter(tool, xml, "FormFiles");
+ outputFilter(tool, xml, "ResourceFiles");
+ for (int x = 0; x < tool.ExtraCompilers.count(); ++x) {
+ outputFilter(tool, xml, tool.ExtraCompilers.at(x));
+ }
+ outputFilter(tool, xml, "RootFiles");
+ xml << closetag(q_Files)
+ << tag(_Globals)
+ << data(); // No "/>" end tag
+}
+
+void VCProjectWriter::write(XmlOutput &xml, const VCCLCompilerTool &tool)
+{
+ xml << tag(_Tool)
+ << attrS(_Name, _VCCLCompilerTool)
+ << attrX(_AdditionalIncludeDirectories, tool.AdditionalIncludeDirectories)
+ << attrX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrX(_AdditionalUsingDirectories, tool.AdditionalUsingDirectories)
+ << attrS(_AssemblerListingLocation, tool.AssemblerListingLocation)
+ << attrE(_AssemblerOutput, tool.AssemblerOutput, /*ifNot*/ asmListingNone)
+ << attrE(_BasicRuntimeChecks, tool.BasicRuntimeChecks, /*ifNot*/ runtimeBasicCheckNone)
+ << attrE(_BrowseInformation, tool.BrowseInformation, /*ifNot*/ brInfoNone)
+ << attrS(_BrowseInformationFile, tool.BrowseInformationFile)
+ << attrT(_BufferSecurityCheck, tool.BufferSecurityCheck)
+ << attrE(_CallingConvention, tool.CallingConvention, /*ifNot*/ callConventionDefault)
+ << attrE(_CompileAs, tool.CompileAs, compileAsDefault)
+ << attrE(_CompileAsManaged, tool.CompileAsManaged, /*ifNot*/ managedDefault)
+ << attrT(_CompileOnly, tool.CompileOnly)
+ << attrE(_DebugInformationFormat, tool.DebugInformationFormat, /*ifNot*/ debugUnknown)
+ << attrT(_DefaultCharIsUnsigned, tool.DefaultCharIsUnsigned)
+ << attrT(_Detect64BitPortabilityProblems, tool.Detect64BitPortabilityProblems)
+ << attrT(_DisableLanguageExtensions, tool.DisableLanguageExtensions)
+ << attrX(_DisableSpecificWarnings, tool.DisableSpecificWarnings)
+ << attrE(_EnableEnhancedInstructionSet, tool.EnableEnhancedInstructionSet, /*ifnot*/ archNotSet)
+ << attrT(_EnableFiberSafeOptimizations, tool.EnableFiberSafeOptimizations)
+ << attrT(_EnableFunctionLevelLinking, tool.EnableFunctionLevelLinking)
+ << attrT(_EnableIntrinsicFunctions, tool.EnableIntrinsicFunctions)
+ << xformExceptionHandlingNET2005(tool.ExceptionHandling, tool.config->CompilerVersion)
+ << attrT(_ExpandAttributedSource, tool.ExpandAttributedSource)
+ << attrE(_FavorSizeOrSpeed, tool.FavorSizeOrSpeed, /*ifNot*/ favorNone)
+
+ << attrE(_FloatingPointModel, tool.FloatingPointModel, /*ifNot*/ floatingPointNotSet)
+ << attrT(_FloatingPointExceptions, tool.FloatingPointExceptions)
+
+ << attrT(_ForceConformanceInForLoopScope, tool.ForceConformanceInForLoopScope)
+ << attrX(_ForcedIncludeFiles, tool.ForcedIncludeFiles)
+ << attrX(_ForcedUsingFiles, tool.ForcedUsingFiles)
+ << attrE(_GeneratePreprocessedFile, tool.GeneratePreprocessedFile, /*ifNot*/ preprocessUnknown)
+ << attrT(_GlobalOptimizations, tool.GlobalOptimizations)
+ << attrT(_IgnoreStandardIncludePath, tool.IgnoreStandardIncludePath)
+ << attrT(_ImproveFloatingPointConsistency, tool.ImproveFloatingPointConsistency)
+ << attrE(_InlineFunctionExpansion, tool.InlineFunctionExpansion, /*ifNot*/ expandDefault)
+ << attrT(_KeepComments, tool.KeepComments)
+ << attrT(_MinimalRebuild, tool.MinimalRebuild)
+ << attrS(_ObjectFile, tool.ObjectFile)
+ << attrT(_OmitFramePointers, tool.OmitFramePointers)
+ << attrT(_OpenMP, tool.OpenMP)
+ << attrE(_Optimization, tool.Optimization, /*ifNot*/ optimizeDefault)
+ << attrE(_OptimizeForProcessor, tool.OptimizeForProcessor, /*ifNot*/ procOptimizeBlended)
+ << attrT(_OptimizeForWindowsApplication, tool.OptimizeForWindowsApplication)
+ << attrS(_OutputFile, tool.OutputFile)
+ << attrS(_PrecompiledHeaderFile, tool.PrecompiledHeaderFile)
+ << attrS(_PrecompiledHeaderThrough, tool.PrecompiledHeaderThrough)
+ << attrX(_PreprocessorDefinitions, tool.PreprocessorDefinitions)
+ << (tool.ProgramDataBaseFileName.isNull() ? noxml() : attr(_ProgramDataBaseFileName, tool.ProgramDataBaseFileName))
+ << attrE(_RuntimeLibrary, tool.RuntimeLibrary, /*ifNot*/ rtUnknown)
+ << attrT(_RuntimeTypeInfo, tool.RuntimeTypeInfo)
+ << attrT(_ShowIncludes, tool.ShowIncludes)
+ << attrT(_SmallerTypeCheck, tool.SmallerTypeCheck)
+ << attrT(_StringPooling, tool.StringPooling)
+ << attrE(_StructMemberAlignment, tool.StructMemberAlignment, /*ifNot*/ alignNotSet)
+ << attrT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+ << attrT(_TreatWChar_tAsBuiltInType, tool.TreatWChar_tAsBuiltInType)
+ << attrT(_TurnOffAssemblyGeneration, tool.TurnOffAssemblyGeneration)
+ << attrT(_UndefineAllPreprocessorDefinitions, tool.UndefineAllPreprocessorDefinitions)
+ << attrX(_UndefinePreprocessorDefinitions, tool.UndefinePreprocessorDefinitions)
+ << xformUsePrecompiledHeaderForNET2005(tool.UsePrecompiledHeader, tool.config->CompilerVersion)
+ << attrT(_WarnAsError, tool.WarnAsError)
+ << attrE(_WarningLevel, tool.WarningLevel, /*ifNot*/ warningLevelUnknown)
+ << attrT(_WholeProgramOptimization, tool.WholeProgramOptimization)
+ << attrE(_CompileForArchitecture, tool.CompileForArchitecture, /*ifNot*/ archUnknown)
+ << attrT(_InterworkCalls, tool.InterworkCalls)
+
+ << closetag(_Tool);
+}
+
+void VCProjectWriter::write(XmlOutput &xml, const VCLinkerTool &tool)
+{
+ xml << tag(_Tool)
+ << attrS(_Name, _VCLinkerTool)
+ << attrX(_AdditionalDependencies, tool.AdditionalDependencies, " ")
+ << attrX(_AdditionalLibraryDirectories, tool.AdditionalLibraryDirectories)
+ << attrX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrX(_AddModuleNamesToAssembly, tool.AddModuleNamesToAssembly)
+ << attrS(_BaseAddress, tool.BaseAddress)
+ << attrX(_DelayLoadDLLs, tool.DelayLoadDLLs)
+ << attrE(_EnableCOMDATFolding, tool.EnableCOMDATFolding, /*ifNot*/ optFoldingDefault)
+ << attrS(_EntryPointSymbol, tool.EntryPointSymbol)
+ << attrX(_ForceSymbolReferences, tool.ForceSymbolReferences)
+ << attrS(_FunctionOrder, tool.FunctionOrder)
+ << attrT(_GenerateDebugInformation, tool.GenerateDebugInformation)
+ << attrT(_GenerateMapFile, tool.GenerateMapFile)
+ << attrL(_HeapCommitSize, tool.HeapCommitSize, /*ifNot*/ -1)
+ << attrL(_HeapReserveSize, tool.HeapReserveSize, /*ifNot*/ -1)
+ << attrT(_IgnoreAllDefaultLibraries, tool.IgnoreAllDefaultLibraries)
+ << attrX(_IgnoreDefaultLibraryNames, tool.IgnoreDefaultLibraryNames)
+ << attrT(_IgnoreEmbeddedIDL, tool.IgnoreEmbeddedIDL)
+ << attrT(_IgnoreImportLibrary, tool.IgnoreImportLibrary)
+ << attrS(_ImportLibrary, tool.ImportLibrary)
+ << attrE(_LargeAddressAware, tool.LargeAddressAware, /*ifNot*/ addrAwareDefault)
+ << attrT(_LinkDLL, tool.LinkDLL)
+ << attrE(_LinkIncremental, tool.LinkIncremental, /*ifNot*/ linkIncrementalDefault)
+ << attrE(_LinkTimeCodeGeneration, tool.LinkTimeCodeGeneration)
+ << attrS(_LinkToManagedResourceFile, tool.LinkToManagedResourceFile)
+ << attrT(_MapExports, tool.MapExports)
+ << attrS(_MapFileName, tool.MapFileName)
+ << attrT(_MapLines, tool.MapLines)
+ << attrS(_MergedIDLBaseFileName, tool.MergedIDLBaseFileName)
+ << attrS(_MergeSections, tool.MergeSections)
+ << attrS(_MidlCommandFile, tool.MidlCommandFile)
+ << attrS(_ModuleDefinitionFile, tool.ModuleDefinitionFile)
+ << attrE(_OptimizeForWindows98, tool.OptimizeForWindows98, /*ifNot*/ optWin98Default)
+ << attrE(_OptimizeReferences, tool.OptimizeReferences, /*ifNot*/ optReferencesDefault)
+ << attrS(_OutputFile, tool.OutputFile)
+ << attr(_ProgramDatabaseFile, tool.ProgramDatabaseFile)
+ << attrT(_RegisterOutput, tool.RegisterOutput)
+ << attrT(_ResourceOnlyDLL, tool.ResourceOnlyDLL)
+ << attrT(_SetChecksum, tool.SetChecksum)
+ << attrE(_ShowProgress, tool.ShowProgress, /*ifNot*/ linkProgressNotSet)
+ << attrL(_StackCommitSize, tool.StackCommitSize, /*ifNot*/ -1)
+ << attrL(_StackReserveSize, tool.StackReserveSize, /*ifNot*/ -1)
+ << attrS(_StripPrivateSymbols, tool.StripPrivateSymbols)
+ << attrE(_SubSystem, tool.SubSystem)
+ << attrT(_SupportUnloadOfDelayLoadedDLL, tool.SupportUnloadOfDelayLoadedDLL)
+ << attrT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+ << attrT(_SwapRunFromCD, tool.SwapRunFromCD)
+ << attrT(_SwapRunFromNet, tool.SwapRunFromNet)
+ << attrE(_TargetMachine, tool.TargetMachine, /*ifNot*/ machineNotSet)
+ << attrE(_TerminalServerAware, tool.TerminalServerAware, /*ifNot*/ termSvrAwareDefault)
+ << attrT(_TurnOffAssemblyGeneration, tool.TurnOffAssemblyGeneration)
+ << attrS(_TypeLibraryFile, tool.TypeLibraryFile)
+ << attrL(_TypeLibraryResourceID, tool.TypeLibraryResourceID, /*ifNot*/ rcUseDefault)
+ << attrS(_Version, tool.Version)
+ << closetag(_Tool);
+}
+
+void VCProjectWriter::write(XmlOutput &xml, const VCMIDLTool &tool)
+{
+ xml << tag(_Tool)
+ << attrS(_Name, _VCMIDLTool)
+ << attrX(_AdditionalIncludeDirectories, tool.AdditionalIncludeDirectories)
+ << attrX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrX(_CPreprocessOptions, tool.CPreprocessOptions)
+ << attrE(_DefaultCharType, tool.DefaultCharType)
+ << attrS(_DLLDataFileName, tool.DLLDataFileName)
+ << attrE(_EnableErrorChecks, tool.EnableErrorChecks)
+ << attrT(_ErrorCheckAllocations, tool.ErrorCheckAllocations)
+ << attrT(_ErrorCheckBounds, tool.ErrorCheckBounds)
+ << attrT(_ErrorCheckEnumRange, tool.ErrorCheckEnumRange)
+ << attrT(_ErrorCheckRefPointers, tool.ErrorCheckRefPointers)
+ << attrT(_ErrorCheckStubData, tool.ErrorCheckStubData)
+ << attrX(_FullIncludePath, tool.FullIncludePath)
+ << attrT(_GenerateStublessProxies, tool.GenerateStublessProxies)
+ << attrT(_GenerateTypeLibrary, tool.GenerateTypeLibrary)
+ << attrS(_HeaderFileName, tool.HeaderFileName)
+ << attrT(_IgnoreStandardIncludePath, tool.IgnoreStandardIncludePath)
+ << attrS(_InterfaceIdentifierFileName, tool.InterfaceIdentifierFileName)
+ << attrT(_MkTypLibCompatible, tool.MkTypLibCompatible)
+ << attrS(_OutputDirectory, tool.OutputDirectory)
+ << attrX(_PreprocessorDefinitions, tool.PreprocessorDefinitions)
+ << attrS(_ProxyFileName, tool.ProxyFileName)
+ << attrS(_RedirectOutputAndErrors, tool.RedirectOutputAndErrors)
+ << attrE(_StructMemberAlignment, tool.StructMemberAlignment, /*ifNot*/ midlAlignNotSet)
+ << attrT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+ << attrE(_TargetEnvironment, tool.TargetEnvironment, /*ifNot*/ midlTargetNotSet)
+ << attrS(_TypeLibraryName, tool.TypeLibraryName)
+ << attrX(_UndefinePreprocessorDefinitions, tool.UndefinePreprocessorDefinitions)
+ << attrT(_ValidateParameters, tool.ValidateParameters)
+ << attrT(_WarnAsError, tool.WarnAsError)
+ << attrE(_WarningLevel, tool.WarningLevel)
+ << closetag(_Tool);
+}
+
+void VCProjectWriter::write(XmlOutput &xml, const VCCustomBuildTool &tool)
+{
+ xml << tag(_Tool)
+ << attrS(_Name, tool.ToolName)
+ << attrX(_AdditionalDependencies, tool.AdditionalDependencies, ";")
+ << attrS(_CommandLine, tool.CommandLine.join(vcCommandSeparator()))
+ << attrS(_Description, tool.Description)
+ << attrX(_Outputs, tool.Outputs, ";")
+ << attrS(_Path, tool.ToolPath)
+ << closetag(_Tool);
+}
+
+void VCProjectWriter::write(XmlOutput &xml, const VCLibrarianTool &tool)
+{
+ xml
+ << tag(_Tool)
+ << attrS(_Name, _VCLibrarianTool)
+ << attrX(_AdditionalDependencies, tool.AdditionalDependencies)
+ << attrX(_AdditionalLibraryDirectories, tool.AdditionalLibraryDirectories)
+ << attrX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrX(_ExportNamedFunctions, tool.ExportNamedFunctions)
+ << attrX(_ForceSymbolReferences, tool.ForceSymbolReferences)
+ << attrT(_IgnoreAllDefaultLibraries, tool.IgnoreAllDefaultLibraries)
+ << attrX(_IgnoreDefaultLibraryNames, tool.IgnoreDefaultLibraryNames)
+ << attrS(_ModuleDefinitionFile, tool.ModuleDefinitionFile)
+ << attrS(_OutputFile, tool.OutputFile)
+ << attrT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+ << closetag(_Tool);
+}
+
+void VCProjectWriter::write(XmlOutput &xml, const VCResourceCompilerTool &tool)
+{
+ xml
+ << tag(_Tool)
+ << attrS(_Name, _VCResourceCompilerTool)
+ << attrS(_Path, tool.ToolPath)
+ << attrX(_AdditionalIncludeDirectories, tool.AdditionalIncludeDirectories)
+ << attrX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrE(_Culture, tool.Culture, /*ifNot*/ rcUseDefault)
+ << attrX(_FullIncludePath, tool.FullIncludePath)
+ << attrT(_IgnoreStandardIncludePath, tool.IgnoreStandardIncludePath)
+ << attrX(_PreprocessorDefinitions, tool.PreprocessorDefinitions)
+ << attrS(_ResourceOutputFileName, tool.ResourceOutputFileName)
+ << attrE(_ShowProgress, tool.ShowProgress, /*ifNot*/ linkProgressNotSet)
+ << closetag(_Tool);
+}
+
+void VCProjectWriter::write(XmlOutput &xml, const VCEventTool &tool)
+{
+ xml
+ << tag(_Tool)
+ << attrS(_Name, tool.ToolName)
+ << attrS(_Path, tool.ToolPath)
+ << attrS(_CommandLine, tool.CommandLine.join(vcCommandSeparator()))
+ << attrS(_Description, tool.Description)
+ << attrT(_ExcludedFromBuild, tool.ExcludedFromBuild)
+ << closetag(_Tool);
+}
+
+void VCProjectWriter::write(XmlOutput &xml, const VCDeploymentTool &tool)
+{
+ if (tool.AdditionalFiles.isEmpty())
+ return;
+ xml << tag(tool.DeploymentTag)
+ << attrS(_RemoteDirectory, tool.RemoteDirectory)
+ << attrE(_RegisterOutput, tool.RegisterOutput)
+ << attrS(_AdditionalFiles, tool.AdditionalFiles)
+ << closetag(tool.DeploymentTag);
+}
+
+void VCProjectWriter::write(XmlOutput &xml, const VCConfiguration &tool)
+{
+ xml << tag(_Configuration)
+ << attrS(_Name, tool.Name)
+ << attrS(_OutputDirectory, tool.OutputDirectory)
+ << attrT(_ATLMinimizesCRunTimeLibraryUsage, tool.ATLMinimizesCRunTimeLibraryUsage)
+ << attrT(_BuildBrowserInformation, tool.BuildBrowserInformation)
+ << attrE(_CharacterSet, tool.CharacterSet, /*ifNot*/ charSetNotSet)
+ << attrE(_ConfigurationType, tool.ConfigurationType)
+ << attrS(_DeleteExtensionsOnClean, tool.DeleteExtensionsOnClean)
+ << attrS(_ImportLibrary, tool.ImportLibrary)
+ << attrS(_IntermediateDirectory, tool.IntermediateDirectory)
+ << attrS(_PrimaryOutput, tool.PrimaryOutput)
+ << attrS(_ProgramDatabase, tool.ProgramDatabase)
+ << attrT(_RegisterOutput, tool.RegisterOutput)
+ << attrE(_UseOfATL, tool.UseOfATL, /*ifNot*/ useATLNotSet)
+ << attrE(_UseOfMfc, tool.UseOfMfc)
+ << attrT(_WholeProgramOptimization, tool.WholeProgramOptimization);
+ write(xml, tool.compiler);
+ write(xml, tool.custom);
+ if (tool.ConfigurationType == typeStaticLibrary)
+ write(xml, tool.librarian);
+ else
+ write(xml, tool.linker);
+ write(xml, tool.idl);
+ write(xml, tool.postBuild);
+ write(xml, tool.preBuild);
+ write(xml, tool.preLink);
+ write(xml, tool.resource);
+ write(xml, tool.deployment);
+ xml << closetag(_Configuration);
+}
+
+void VCProjectWriter::write(XmlOutput &xml, VCFilter &tool)
+{
+ if(!tool.Files.count())
+ return;
+
+ if (!tool.Name.isEmpty()) {
+ xml << tag(_Filter)
+ << attrS(_Name, tool.Name)
+ << attrS(_Filter, tool.Filter)
+ << attrS(_UniqueIdentifier, tool.Guid)
+ << attrT(_ParseFiles, tool.ParseFiles);
+ }
+ for (int i = 0; i < tool.Files.count(); ++i) {
+ const VCFilterFile &info = tool.Files.at(i);
+ xml << tag(q_File)
+ << attrS(_RelativePath, Option::fixPathToLocalOS(info.file))
+ << data(); // In case no custom builds, to avoid "/>" endings
+ outputFileConfig(tool, xml, tool.Files.at(i).file);
+ xml << closetag(q_File);
+ }
+ if (!tool.Name.isEmpty())
+ xml << closetag(_Filter);
+}
+
+// outputs a given filter for all existing configurations of a project
+void VCProjectWriter::outputFilter(VCProject &project, XmlOutput &xml, const QString &filtername)
+{
+ Node *root;
+ if (project.SingleProjects.at(0).flat_files)
+ root = new FlatNode;
+ else
+ root = new TreeNode;
+
+ QString name, extfilter, guid;
+ triState parse;
+
+ for (int i = 0; i < project.SingleProjects.count(); ++i) {
+ VCFilter filter;
+ const VCProjectSingleConfig &projectSingleConfig = project.SingleProjects.at(i);
+ if (filtername == "RootFiles") {
+ filter = projectSingleConfig.RootFiles;
+ } else if (filtername == "Sources") {
+ filter = projectSingleConfig.SourceFiles;
+ } else if (filtername == "Headers") {
+ filter = projectSingleConfig.HeaderFiles;
+ } else if (filtername == "GeneratedFiles") {
+ filter = projectSingleConfig.GeneratedFiles;
+ } else if (filtername == "LexYaccFiles") {
+ filter = projectSingleConfig.LexYaccFiles;
+ } else if (filtername == "TranslationFiles") {
+ filter = projectSingleConfig.TranslationFiles;
+ } else if (filtername == "FormFiles") {
+ filter = projectSingleConfig.FormFiles;
+ } else if (filtername == "ResourceFiles") {
+ filter = projectSingleConfig.ResourceFiles;
+ } else {
+ // ExtraCompilers
+ filter = project.SingleProjects[i].filterForExtraCompiler(filtername);
+ }
+
+ // Merge all files in this filter to root tree
+ for (int x = 0; x < filter.Files.count(); ++x)
+ root->addElement(filter.Files.at(x));
+
+ // Save filter setting from first filter. Next filters
+ // may differ but we cannot handle that. (ex. extfilter)
+ if (name.isEmpty()) {
+ name = filter.Name;
+ extfilter = filter.Filter;
+ parse = filter.ParseFiles;
+ guid = filter.Guid;
+ }
+ }
+
+ if (!root->hasElements())
+ return;
+
+ // Actual XML output ----------------------------------
+ if (!name.isEmpty()) {
+ xml << tag(_Filter)
+ << attrS(_Name, name)
+ << attrS(_Filter, extfilter)
+ << attrS(_UniqueIdentifier, guid)
+ << attrT(_ParseFiles, parse);
+ }
+ root->generateXML(xml, "", project, filtername); // output root tree
+ if (!name.isEmpty())
+ xml << closetag(_Filter);
+}
+
+// Output all configurations (by filtername) for a file (by info)
+// A filters config output is in VCFilter.outputFileConfig()
+void VCProjectWriter::outputFileConfigs(VCProject &project, XmlOutput &xml, const VCFilterFile &info, const QString &filtername)
+{
+ xml << tag(q_File)
+ << attrS(_RelativePath, Option::fixPathToLocalOS(info.file));
+ for (int i = 0; i < project.SingleProjects.count(); ++i) {
+ VCFilter filter;
+ const VCProjectSingleConfig &projectSingleConfig = project.SingleProjects.at(i);
+ if (filtername == "RootFiles") {
+ filter = projectSingleConfig.RootFiles;
+ } else if (filtername == "Sources") {
+ filter = projectSingleConfig.SourceFiles;
+ } else if (filtername == "Headers") {
+ filter = projectSingleConfig.HeaderFiles;
+ } else if (filtername == "GeneratedFiles") {
+ filter = projectSingleConfig.GeneratedFiles;
+ } else if (filtername == "LexYaccFiles") {
+ filter = projectSingleConfig.LexYaccFiles;
+ } else if (filtername == "TranslationFiles") {
+ filter = projectSingleConfig.TranslationFiles;
+ } else if (filtername == "FormFiles") {
+ filter = projectSingleConfig.FormFiles;
+ } else if (filtername == "ResourceFiles") {
+ filter = projectSingleConfig.ResourceFiles;
+ } else {
+ // ExtraCompilers
+ filter = project.SingleProjects[i].filterForExtraCompiler(filtername);
+ }
+
+ if (filter.Config) // only if the filter is not empty
+ outputFileConfig(filter, xml, info.file);
+ }
+ xml << closetag(q_File);
+}
+
+void VCProjectWriter::outputFileConfig(VCFilter &filter, XmlOutput &xml, const QString &filename)
+{
+ // Clearing each filter tool
+ filter.useCustomBuildTool = false;
+ filter.useCompilerTool = false;
+ filter.CustomBuildTool = VCCustomBuildTool();
+ filter.CompilerTool = VCCLCompilerTool();
+
+ // Unset some default options
+ filter.CustomBuildTool.config = filter.Config;
+ filter.CompilerTool.BufferSecurityCheck = unset;
+ filter.CompilerTool.DebugInformationFormat = debugUnknown;
+ filter.CompilerTool.ExceptionHandling = ehDefault;
+ filter.CompilerTool.GeneratePreprocessedFile = preprocessUnknown;
+ filter.CompilerTool.Optimization = optimizeDefault;
+ filter.CompilerTool.ProgramDataBaseFileName.clear();
+ filter.CompilerTool.RuntimeLibrary = rtUnknown;
+ filter.CompilerTool.WarningLevel = warningLevelUnknown;
+ filter.CompilerTool.config = filter.Config;
+
+ bool inBuild = false;
+ VCFilterFile info;
+ for (int i = 0; i < filter.Files.count(); ++i) {
+ if (filter.Files.at(i).file == filename) {
+ info = filter.Files.at(i);
+ inBuild = true;
+ }
+ }
+ inBuild &= !info.excludeFromBuild;
+
+ if (inBuild) {
+ filter.addExtraCompiler(info);
+ if(filter.Project->usePCH)
+ filter.modifyPCHstage(info.file);
+ } else {
+ // Excluded files uses an empty compiler stage
+ if(info.excludeFromBuild)
+ filter.useCompilerTool = true;
+ }
+
+ // Actual XML output ----------------------------------
+ if (filter.useCustomBuildTool || filter.useCompilerTool || !inBuild) {
+ xml << tag(_FileConfiguration)
+ << attr(_Name, filter.Config->Name)
+ << (!inBuild ? attrS(_ExcludedFromBuild, "true") : noxml());
+ if (filter.useCustomBuildTool)
+ filter.Project->projectWriter->write(xml, filter.CustomBuildTool);
+ if (filter.useCompilerTool)
+ filter.Project->projectWriter->write(xml, filter.CompilerTool);
+ xml << closetag(_FileConfiguration);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/msvc_objectmodel.h b/qmake/generators/win32/msvc_objectmodel.h
new file mode 100644
index 0000000000..3e62fb41ee
--- /dev/null
+++ b/qmake/generators/win32/msvc_objectmodel.h
@@ -0,0 +1,1141 @@
+/****************************************************************************
+**
+** 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 MSVC_OBJECTMODEL_H
+#define MSVC_OBJECTMODEL_H
+
+#include "project.h"
+#include "xmloutput.h"
+#include <qatomic.h>
+#include <qlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qmap.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+enum DotNET {
+ NETUnknown = 0,
+ NET2002 = 0x70,
+ NET2003 = 0x71,
+ NET2005 = 0x80,
+ NET2008 = 0x90,
+ NET2010 = 0xa0
+};
+
+/*
+ This Object model is of course VERY simplyfied,
+ and does not actually follow the original MSVC
+ object model. However, it fulfilles the basic
+ needs for qmake
+*/
+
+/*
+ If a triState value is 'unset' then the
+ corresponding property is not in the output,
+ forcing the tool to utilize default values.
+ False/True values will be in the output...
+*/
+enum customBuildCheck {
+ none,
+ mocSrc,
+ mocHdr,
+ lexyacc
+};
+enum triState {
+ unset = -1,
+ _False = 0,
+ _True = 1
+};
+
+triState operator!(const triState &rhs);
+
+enum addressAwarenessType {
+ addrAwareDefault,
+ addrAwareNoLarge,
+ addrAwareLarge
+};
+enum asmListingOption {
+ asmListingNone,
+ asmListingAssemblyOnly,
+ asmListingAsmMachineSrc,
+ asmListingAsmMachine,
+ asmListingAsmSrc
+};
+enum basicRuntimeCheckOption {
+ runtimeBasicCheckNone,
+ runtimeCheckStackFrame,
+ runtimeCheckUninitVariables,
+ runtimeBasicCheckAll
+};
+enum browseInfoOption {
+ brInfoNone,
+ brAllInfo,
+ brNoLocalSymbols
+};
+enum callingConventionOption {
+ callConventionDefault = -1,
+ callConventionCDecl,
+ callConventionFastCall,
+ callConventionStdCall
+};
+enum charSet {
+ charSetNotSet,
+ charSetUnicode,
+ charSetMBCS
+};
+enum compileAsManagedOptions {
+ managedDefault = -1, // Was: noAssembly
+ managedAssembly = 1,
+ managedAssemblyPure = 2, // Old was: Assembly
+ managedAssemblySafe = 3,
+ managedAssemblyOldSyntax = 4
+};
+enum CompileAsOptions{
+ compileAsDefault,
+ compileAsC,
+ compileAsCPlusPlus
+};
+enum ConfigurationTypes {
+ typeUnknown = 0,
+ typeApplication = 1,
+ typeDynamicLibrary = 2,
+ typeStaticLibrary = 4,
+ typeGeneric = 10
+};
+enum debugOption {
+ debugUnknown = -1,
+ debugDisabled,
+ debugOldStyleInfo,
+ debugLineInfoOnly,
+ debugEnabled,
+ debugEditAndContinue
+};
+enum eAppProtectionOption {
+ eAppProtectUnchanged,
+ eAppProtectLow,
+ eAppProtectMedium,
+ eAppProtectHigh
+};
+enum enhancedInstructionSetOption {
+ archNotSet = 0,
+ archSSE = 1,
+ archSSE2 = 2
+};
+enum exceptionHandling {
+ ehDefault = -1,
+ ehNone = 0,
+ ehNoSEH = 1,
+ ehSEH = 2
+};
+enum enumResourceLangID {
+ rcUseDefault = 0,
+ rcAfrikaans = 1078,
+ rcAlbanian = 1052,
+ rcArabicAlgeria = 5121,
+ rcArabicBahrain = 15361,
+ rcArabicEgypt = 3073,
+ rcArabicIraq = 2049,
+ rcArabicJordan = 11265,
+ rcArabicKuwait = 13313,
+ rcArabicLebanon = 12289,
+ rcArabicLibya = 4097,
+ rcArabicMorocco = 6145,
+ rcArabicOman = 8193,
+ rcArabicQatar = 16385,
+ rcArabicSaudi = 1025,
+ rcArabicSyria = 10241,
+ rcArabicTunisia = 7169,
+ rcArabicUnitedArabEmirates = 14337,
+ rcArabicYemen = 9217,
+ rcBasque = 1069,
+ rcBulgarian = 1026,
+ rcByelorussian = 1059,
+ rcCatalan = 1027,
+ rcChineseHongKong = 3076,
+ rcChinesePRC = 2052,
+ rcChineseSingapore = 4100,
+ rcChineseTaiwan = 1028,
+ rcCroatian = 1050,
+ rcCzech = 1029,
+ rcDanish = 1030,
+ rcDutchBelgium = 2067,
+ rcDutchStandard = 1043,
+ rcEnglishAustralia = 3081,
+ rcEnglishBritain = 2057,
+ rcEnglishCanada = 4105,
+ RcEnglishCaribbean = 9225,
+ rcEnglishIreland = 6153,
+ rcEnglishJamaica = 8201,
+ rcEnglishNewZealand = 5129,
+ rcEnglishSouthAfrica = 7177,
+ rcEnglishUS = 1033,
+ rcEstonian = 1061,
+ rcFarsi = 1065,
+ rcFinnish = 1035,
+ rcFrenchBelgium = 2060,
+ rcFrenchCanada = 3084,
+ rcFrenchLuxembourg = 5132,
+ rcFrenchStandard = 1036,
+ rcFrenchSwitzerland = 4108,
+ rcGermanAustria = 3079,
+ rcGermanLichtenstein = 5127,
+ rcGermanLuxembourg = 4103,
+ rcGermanStandard = 1031,
+ rcGermanSwitzerland = 2055,
+ rcGreek = 1032,
+ rcHebrew = 1037,
+ rcHungarian = 1038,
+ rcIcelandic = 1039,
+ rcIndonesian = 1057,
+ rcItalianStandard = 1040,
+ rcItalianSwitzerland = 2064,
+ rcJapanese = 1041,
+ rcKorean = 1042,
+ rcKoreanJohab = 2066,
+ rcLatvian = 1062,
+ rcLithuanian = 1063,
+ rcNorwegianBokmal = 1044,
+ rcNorwegianNynorsk = 2068,
+ rcPolish = 1045,
+ rcPortugueseBrazilian = 1046,
+ rcPortugueseStandard = 2070,
+ rcRomanian = 1048,
+ rcRussian = 1049,
+ rcSerbian = 2074,
+ rcSlovak = 1051,
+ rcSpanishArgentina = 11274,
+ rcSpanishBolivia = 16394,
+ rcSpanishChile = 13322,
+ rcSpanishColombia = 9226,
+ rcSpanishCostaRica = 5130,
+ rcSpanishDominicanRepublic = 7178,
+ rcSpanishEcuador = 12298,
+ rcSpanishGuatemala = 4106,
+ rcSpanishMexico = 2058,
+ rcSpanishModern = 3082,
+ rcSpanishPanama = 6154,
+ rcSpanishParaguay = 15370,
+ rcSpanishPeru = 10250,
+ rcSpanishTraditional = 1034,
+ rcSpanishUruguay = 14346,
+ rcSpanishVenezuela = 8202,
+ rcSwedish = 1053,
+ rcThai = 1054,
+ rcTurkish = 1055,
+ rcUkrainian = 1058,
+ rcUrdu = 1056
+};
+enum enumSccEvent {
+ eProjectInScc,
+ ePreDirtyNotification
+};
+enum favorSizeOrSpeedOption {
+ favorNone,
+ favorSpeed,
+ favorSize
+};
+enum floatingPointModel {
+ floatingPointNotSet = -1,
+ floatingPointPrecise,
+ floatingPointStrict,
+ floatingPointFast
+};
+enum genProxyLanguage {
+ genProxyNative,
+ genProxyManaged
+};
+enum inlineExpansionOption {
+ expandDisable,
+ expandOnlyInline,
+ expandAnySuitable,
+ expandDefault // Not useful number, but stops the output
+};
+enum linkIncrementalType {
+ linkIncrementalDefault,
+ linkIncrementalNo,
+ linkIncrementalYes
+};
+enum linkProgressOption {
+ linkProgressNotSet,
+ linkProgressAll,
+ linkProgressLibs
+};
+enum machineTypeOption {
+ machineNotSet,
+ machineX86,
+ machineX64 = 17
+};
+enum midlCharOption {
+ midlCharUnsigned,
+ midlCharSigned,
+ midlCharAscii7
+};
+enum midlErrorCheckOption {
+ midlEnableCustom,
+ midlDisableAll,
+ midlEnableAll
+};
+enum midlStructMemberAlignOption {
+ midlAlignNotSet,
+ midlAlignSingleByte,
+ midlAlignTwoBytes,
+ midlAlignFourBytes,
+ midlAlignEightBytes,
+ midlAlignSixteenBytes
+};
+enum midlTargetEnvironment {
+ midlTargetNotSet,
+ midlTargetWin32,
+ midlTargetWin64
+};
+enum midlWarningLevelOption {
+ midlWarningLevel_0,
+ midlWarningLevel_1,
+ midlWarningLevel_2,
+ midlWarningLevel_3,
+ midlWarningLevel_4
+};
+enum optFoldingType {
+ optFoldingDefault,
+ optNoFolding,
+ optFolding
+};
+enum optimizeOption {
+ optimizeDisabled,
+ optimizeMinSpace,
+ optimizeMaxSpeed,
+ optimizeFull,
+ optimizeCustom,
+ optimizeDefault // Not useful number, but stops the output
+};
+enum optRefType {
+ optReferencesDefault,
+ optNoReferences,
+ optReferences
+};
+enum optWin98Type {
+ optWin98Default,
+ optWin98No,
+ optWin98Yes
+};
+enum optLinkTimeCodeGenType {
+ optLTCGDefault,
+ optLTCGEnabled,
+ optLTCGInstrument,
+ optLTCGOptimize,
+ optLTCGUpdate
+};
+enum pchOption {
+ pchUnset = -1,
+ pchNone,
+ pchCreateUsingSpecific,
+ pchGenerateAuto,
+ pchUseUsingSpecific
+};
+enum preprocessOption {
+ preprocessUnknown = -1,
+ preprocessNo,
+ preprocessYes,
+ preprocessNoLineNumbers
+};
+enum ProcessorOptimizeOption {
+ procOptimizeBlended, //GB
+ procOptimizePentium, //G5
+ procOptimizePentiumProAndAbove, //G6
+ procOptimizePentium4AndAbove //G7
+};
+enum RegisterDeployOption {
+ registerNo = 0,
+ registerYes
+};
+enum RemoteDebuggerType {
+ DbgLocal,
+ DbgRemote,
+ DbgRemoteTCPIP
+};
+enum runtimeLibraryOption {
+ rtUnknown = -1,
+ rtMultiThreaded,
+ rtMultiThreadedDebug,
+ rtMultiThreadedDLL,
+ rtMultiThreadedDebugDLL,
+ rtSingleThreaded,
+ rtSingleThreadedDebug
+};
+enum structMemberAlignOption {
+ alignNotSet,
+ alignSingleByte,
+ alignTwoBytes,
+ alignFourBytes,
+ alignEightBytes,
+ alignSixteenBytes
+};
+enum subSystemOption {
+ subSystemNotSet,
+ subSystemConsole,
+ subSystemWindows
+};
+enum termSvrAwarenessType {
+ termSvrAwareDefault,
+ termSvrAwareNo,
+ termSvrAwareYes
+};
+enum toolSetType {
+ toolSetUtility,
+ toolSetMakefile,
+ toolSetLinker,
+ toolSetLibrarian,
+ toolSetAll
+};
+enum TypeOfDebugger {
+ DbgNativeOnly,
+ DbgManagedOnly,
+ DbgMixed,
+ DbgAuto
+};
+enum useOfATL {
+ useATLNotSet,
+ useATLStatic,
+ useATLDynamic
+};
+enum useOfMfc {
+ useMfcStdWin,
+ useMfcStatic,
+ useMfcDynamic
+};
+enum useOfArchitecture {
+ archUnknown = -1,
+ archArmv4,
+ archArmv5,
+ archArmv4T,
+ archArmv5T,
+ archMips1 = 0,
+ archMips2 = 1,
+ archMips3 = 2,
+ archMips4 = 3,
+ archMips5 = 4,
+ archMips16 = 5,
+ archMips32 = 6,
+ archMips64 = 7
+};
+enum warningLevelOption {
+ warningLevelUnknown = -1,
+ warningLevel_0,
+ warningLevel_1,
+ warningLevel_2,
+ warningLevel_3,
+ warningLevel_4
+};
+
+
+class VCToolBase {
+protected:
+ // Functions
+ VCToolBase(){}
+ virtual ~VCToolBase(){}
+ virtual bool parseOption(const char* option) = 0;
+public:
+ void parseOptions(QStringList& options) {
+ for (QStringList::ConstIterator it=options.begin(); (it!=options.end()); it++)
+ parseOption((*it).toLatin1());
+ }
+ static QStringList fixCommandLine(const QString &input);
+};
+
+class VCConfiguration;
+class VCProject;
+
+class VCCLCompilerTool : public VCToolBase
+{
+public:
+ // Functions
+ VCCLCompilerTool();
+ virtual ~VCCLCompilerTool(){}
+ bool parseOption(const char* option);
+
+ // Variables
+ QStringList AdditionalIncludeDirectories;
+ QStringList AdditionalOptions;
+ QStringList AdditionalUsingDirectories;
+ QString AssemblerListingLocation;
+ asmListingOption AssemblerOutput;
+ basicRuntimeCheckOption BasicRuntimeChecks;
+ browseInfoOption BrowseInformation;
+ QString BrowseInformationFile;
+ triState BufferSecurityCheck;
+ callingConventionOption CallingConvention;
+ CompileAsOptions CompileAs;
+ compileAsManagedOptions CompileAsManaged;
+ triState CompileOnly;
+ debugOption DebugInformationFormat;
+ triState DefaultCharIsUnsigned;
+ triState Detect64BitPortabilityProblems;
+ triState DisableLanguageExtensions;
+ QStringList DisableSpecificWarnings;
+ enhancedInstructionSetOption EnableEnhancedInstructionSet;
+ triState EnableFiberSafeOptimizations;
+ triState EnableFunctionLevelLinking;
+ triState EnableIntrinsicFunctions;
+ exceptionHandling ExceptionHandling;
+ triState ExpandAttributedSource;
+ favorSizeOrSpeedOption FavorSizeOrSpeed;
+ floatingPointModel FloatingPointModel;
+ triState FloatingPointExceptions;
+ triState ForceConformanceInForLoopScope;
+ QStringList ForcedIncludeFiles;
+ QStringList ForcedUsingFiles;
+ preprocessOption GeneratePreprocessedFile;
+ triState PreprocessSuppressLineNumbers;
+ triState GlobalOptimizations;
+ triState IgnoreStandardIncludePath;
+ triState ImproveFloatingPointConsistency;
+ inlineExpansionOption InlineFunctionExpansion;
+ triState KeepComments;
+ triState MinimalRebuild;
+ QString ObjectFile;
+ triState OmitDefaultLibName;
+ triState OmitFramePointers;
+ triState OpenMP;
+ optimizeOption Optimization;
+ ProcessorOptimizeOption OptimizeForProcessor;
+ triState OptimizeForWindowsApplication;
+ QString OutputFile;
+ QString PrecompiledHeaderFile;
+ QString PrecompiledHeaderThrough;
+ QStringList PreprocessorDefinitions;
+ QString ProgramDataBaseFileName;
+ runtimeLibraryOption RuntimeLibrary;
+ triState RuntimeTypeInfo;
+ triState ShowIncludes;
+ triState SmallerTypeCheck;
+ triState StringPooling;
+ structMemberAlignOption StructMemberAlignment;
+ triState SuppressStartupBanner;
+ triState TreatWChar_tAsBuiltInType;
+ triState TurnOffAssemblyGeneration;
+ triState UndefineAllPreprocessorDefinitions;
+ QStringList UndefinePreprocessorDefinitions;
+ pchOption UsePrecompiledHeader;
+ triState UseUnicodeForAssemblerListing;
+ triState WarnAsError;
+ warningLevelOption WarningLevel;
+ triState WholeProgramOptimization;
+ useOfArchitecture CompileForArchitecture;
+ triState InterworkCalls;
+
+ // VS2010
+ triState EnablePREfast;
+ triState DisplayFullPaths;
+ triState MultiProcessorCompilation;
+ QString MultiProcessorCompilationProcessorCount;
+ triState GenerateXMLDocumentationFiles;
+ QString XMLDocumentationFileName;
+ QString ErrorReporting;
+ triState CreateHotpatchableImage;
+ QString PreprocessOutputPath;
+
+ VCConfiguration* config;
+};
+
+class VCLinkerTool : public VCToolBase
+{
+public:
+ // Functions
+ VCLinkerTool();
+ virtual ~VCLinkerTool(){}
+ bool parseOption(const char* option);
+
+ // Variables
+ QStringList AdditionalDependencies;
+ QStringList AdditionalLibraryDirectories;
+ QStringList AdditionalOptions;
+ QStringList AddModuleNamesToAssembly;
+ QString BaseAddress;
+ triState DataExecutionPrevention;
+ QStringList DelayLoadDLLs;
+ optFoldingType EnableCOMDATFolding;
+ QString EntryPointSymbol;
+ QStringList ForceSymbolReferences;
+ QString FunctionOrder;
+ triState GenerateDebugInformation;
+ triState GenerateMapFile;
+ qlonglong HeapCommitSize;
+ qlonglong HeapReserveSize;
+ triState IgnoreAllDefaultLibraries;
+ QStringList IgnoreDefaultLibraryNames;
+ triState IgnoreEmbeddedIDL;
+ triState IgnoreImportLibrary;
+ QString ImportLibrary;
+ addressAwarenessType LargeAddressAware;
+ triState LinkDLL;
+ linkIncrementalType LinkIncremental;
+ optLinkTimeCodeGenType LinkTimeCodeGeneration;
+ QString LinkToManagedResourceFile;
+ triState MapExports;
+ QString MapFileName;
+ triState MapLines;
+ QString MergedIDLBaseFileName;
+ QString MergeSections; // Should be list?
+ QString MidlCommandFile;
+ QString ModuleDefinitionFile; // Should be list?
+ optWin98Type OptimizeForWindows98;
+ optRefType OptimizeReferences;
+ QString OutputFile;
+ QString ProgramDatabaseFile;
+ triState RandomizedBaseAddress;
+ triState RegisterOutput;
+ triState ResourceOnlyDLL;
+ triState SetChecksum;
+ linkProgressOption ShowProgress;
+ qlonglong StackCommitSize;
+ qlonglong StackReserveSize;
+ QString StripPrivateSymbols; // Should be list?
+ subSystemOption SubSystem;
+ triState SupportUnloadOfDelayLoadedDLL;
+ triState SuppressStartupBanner;
+ triState SwapRunFromCD;
+ triState SwapRunFromNet;
+ machineTypeOption TargetMachine;
+ termSvrAwarenessType TerminalServerAware;
+ triState TreatWarningsAsErrors;
+ triState TurnOffAssemblyGeneration;
+ QString TypeLibraryFile;
+ qlonglong TypeLibraryResourceID;
+ QString Version;
+
+ // VS2010
+ triState GenerateManifest;
+ QStringList AdditionalManifestDependencies;
+ QString ManifestFile;
+ triState EnableUAC;
+ QString UACExecutionLevel;
+ triState UACUIAccess;
+ qlonglong SectionAlignment;
+ triState PreventDllBinding;
+ triState AllowIsolation;
+ triState AssemblyDebug;
+ QStringList AssemblyLinkResource;
+ QString CLRImageType;
+ QString CLRSupportLastError;
+ QString CLRThreadAttribute;
+ triState CLRUnmanagedCodeCheck;
+ triState DelaySign;
+ QString KeyContainer;
+ QString KeyFile;
+ QString LinkErrorReporting;
+
+ VCConfiguration* config;
+};
+
+class VCMIDLTool : public VCToolBase
+{
+public:
+ // Functions
+ VCMIDLTool();
+ virtual ~VCMIDLTool(){}
+ bool parseOption(const char* option);
+
+ // Variables
+ QStringList AdditionalIncludeDirectories;
+ QStringList AdditionalOptions;
+ QStringList CPreprocessOptions;
+ midlCharOption DefaultCharType;
+ QString DLLDataFileName; // Should be list?
+ midlErrorCheckOption EnableErrorChecks;
+ triState ErrorCheckAllocations;
+ triState ErrorCheckBounds;
+ triState ErrorCheckEnumRange;
+ triState ErrorCheckRefPointers;
+ triState ErrorCheckStubData;
+ QStringList FullIncludePath;
+ triState GenerateStublessProxies;
+ triState GenerateTypeLibrary;
+ QString HeaderFileName;
+ triState IgnoreStandardIncludePath;
+ QString InterfaceIdentifierFileName;
+ triState MkTypLibCompatible;
+ QString OutputDirectory;
+ QStringList PreprocessorDefinitions;
+ QString ProxyFileName;
+ QString RedirectOutputAndErrors;
+ midlStructMemberAlignOption StructMemberAlignment;
+ triState SuppressStartupBanner;
+ midlTargetEnvironment TargetEnvironment;
+ QString TypeLibraryName;
+ QStringList UndefinePreprocessorDefinitions;
+ triState ValidateParameters;
+ triState WarnAsError;
+ midlWarningLevelOption WarningLevel;
+
+ // VS 2010
+ triState ApplicationConfigurationMode;
+ QString GenerateClientFiles;
+ QString ClientStubFile;
+ QString TypeLibFormat;
+ triState ValidateAllParameters;
+ triState SuppressCompilerWarnings;
+ QString GenerateServerFiles;
+ QString ServerStubFile;
+ qlonglong LocaleID;
+
+ VCConfiguration* config;
+};
+
+class VCLibrarianTool : public VCToolBase
+{
+public:
+ // Functions
+ VCLibrarianTool();
+ virtual ~VCLibrarianTool(){}
+ bool parseOption(const char*){ return false; }
+
+ // Variables
+ QStringList AdditionalDependencies;
+ QStringList AdditionalLibraryDirectories;
+ QStringList AdditionalOptions;
+ QStringList ExportNamedFunctions;
+ QStringList ForceSymbolReferences;
+ triState IgnoreAllDefaultLibraries;
+ QStringList IgnoreDefaultLibraryNames;
+ QString ModuleDefinitionFile;
+ QString OutputFile;
+ triState SuppressStartupBanner;
+};
+
+class VCCustomBuildTool : public VCToolBase
+{
+public:
+ // Functions
+ VCCustomBuildTool();
+ virtual ~VCCustomBuildTool(){}
+ bool parseOption(const char*){ return false; }
+
+ // Variables
+ QStringList AdditionalDependencies;
+ QStringList CommandLine;
+ QString Description;
+ QStringList Outputs;
+ QString ToolName;
+ QString ToolPath;
+
+ VCConfiguration* config;
+};
+
+class VCResourceCompilerTool : public VCToolBase
+{
+public:
+ // Functions
+ VCResourceCompilerTool();
+ virtual ~VCResourceCompilerTool(){}
+ bool parseOption(const char*){ return false; }
+
+ // Variables
+ QStringList AdditionalIncludeDirectories;
+ QStringList AdditionalOptions;
+ enumResourceLangID Culture;
+ QStringList FullIncludePath;
+ triState IgnoreStandardIncludePath;
+ QStringList PreprocessorDefinitions;
+ QString ResourceOutputFileName;
+ linkProgressOption ShowProgress;
+ QString ToolPath;
+ triState SuppressStartupBanner;
+};
+
+class VCDeploymentTool
+{
+public:
+ // Functions
+ VCDeploymentTool();
+ virtual ~VCDeploymentTool() {}
+
+ // Variables
+ QString DeploymentTag;
+ QString RemoteDirectory;
+ RegisterDeployOption RegisterOutput;
+ QString AdditionalFiles;
+};
+
+class VCEventTool : public VCToolBase
+{
+protected:
+ // Functions
+ VCEventTool(const QString &eventName);
+ virtual ~VCEventTool(){}
+ bool parseOption(const char*){ return false; }
+
+public:
+ // Variables
+ QStringList CommandLine;
+ QString Description;
+ triState ExcludedFromBuild;
+ QString EventName;
+ QString ToolName;
+ QString ToolPath;
+};
+
+class VCPostBuildEventTool : public VCEventTool
+{
+public:
+ VCPostBuildEventTool();
+ ~VCPostBuildEventTool(){}
+};
+
+class VCPreBuildEventTool : public VCEventTool
+{
+public:
+ VCPreBuildEventTool();
+ ~VCPreBuildEventTool(){}
+};
+
+class VCPreLinkEventTool : public VCEventTool
+{
+public:
+ VCPreLinkEventTool();
+ ~VCPreLinkEventTool(){}
+};
+
+class VCConfiguration
+{
+public:
+ // Functions
+ VCConfiguration();
+ ~VCConfiguration(){}
+
+ DotNET CompilerVersion;
+
+ // Variables
+ triState ATLMinimizesCRunTimeLibraryUsage;
+ triState BuildBrowserInformation;
+ charSet CharacterSet;
+ ConfigurationTypes ConfigurationType;
+ QString DeleteExtensionsOnClean;
+ QString ImportLibrary;
+ QString IntermediateDirectory;
+ QString Name; // "ConfigurationName|PlatformName"
+ QString ConfigurationName;
+ QString OutputDirectory;
+ QString PrimaryOutput;
+ QString ProgramDatabase;
+ triState RegisterOutput;
+ useOfATL UseOfATL;
+ useOfMfc UseOfMfc;
+ triState WholeProgramOptimization;
+
+ // XML sub-parts
+ VCCLCompilerTool compiler;
+ VCLinkerTool linker;
+ VCLibrarianTool librarian;
+ VCCustomBuildTool custom;
+ VCMIDLTool idl;
+ VCPostBuildEventTool postBuild;
+ VCPreBuildEventTool preBuild;
+ VCDeploymentTool deployment;
+ VCPreLinkEventTool preLink;
+ VCResourceCompilerTool resource;
+};
+
+struct VCFilterFile
+{
+ VCFilterFile()
+ { excludeFromBuild = false; }
+ VCFilterFile(const QString &filename, bool exclude = false )
+ { file = filename; excludeFromBuild = exclude; }
+ VCFilterFile(const QString &filename, const QString &additional, bool exclude = false )
+ { file = filename; excludeFromBuild = exclude; additionalFile = additional; }
+ bool operator==(const VCFilterFile &other){
+ return file == other.file
+ && additionalFile == other.additionalFile
+ && excludeFromBuild == other.excludeFromBuild;
+ }
+
+ bool excludeFromBuild;
+ QString file;
+ QString additionalFile; // For tools like MOC
+};
+
+#ifndef QT_NO_DEBUG_OUTPUT
+inline QDebug operator<<(QDebug dbg, const VCFilterFile &p)
+{
+ dbg.nospace() << "VCFilterFile(file(" << p.file
+ << ") additionalFile(" << p.additionalFile
+ << ") excludeFromBuild(" << p.excludeFromBuild << "))" << endl;
+ return dbg.space();
+}
+#endif
+
+class VcprojGenerator;
+class VCFilter
+{
+public:
+ // Functions
+ VCFilter();
+ ~VCFilter(){}
+
+ void addFile(const QString& filename);
+ void addFile(const VCFilterFile& fileInfo);
+ void addFiles(const QStringList& fileList);
+ bool addExtraCompiler(const VCFilterFile &info);
+ void modifyPCHstage(QString str);
+
+ // Variables
+ QString Name;
+ QString Filter;
+ QString Guid;
+ triState ParseFiles;
+ VcprojGenerator* Project;
+ VCConfiguration* Config;
+ QList<VCFilterFile> Files;
+
+ customBuildCheck CustomBuild;
+
+ bool useCustomBuildTool;
+ VCCustomBuildTool CustomBuildTool;
+
+ bool useCompilerTool;
+ VCCLCompilerTool CompilerTool;
+};
+
+typedef QList<VCFilter> VCFilterList;
+class VCProjectSingleConfig
+{
+public:
+ enum FilterTypes {
+ None,
+ Source,
+ Header,
+ Generated,
+ LexYacc,
+ Translation,
+ Resources,
+ Extras
+ };
+ // Functions
+ VCProjectSingleConfig(){}
+ ~VCProjectSingleConfig(){}
+
+ // Variables
+ QString Name;
+ QString Version;
+ QString ProjectGUID;
+ QString Keyword;
+ QString SccProjectName;
+ QString SccLocalPath;
+ QString PlatformName;
+
+ // XML sub-parts
+ VCConfiguration Configuration;
+ VCFilter RootFiles;
+ VCFilter SourceFiles;
+ VCFilter HeaderFiles;
+ VCFilter GeneratedFiles;
+ VCFilter LexYaccFiles;
+ VCFilter TranslationFiles;
+ VCFilter FormFiles;
+ VCFilter ResourceFiles;
+ VCFilterList ExtraCompilersFiles;
+
+ bool flat_files;
+
+ // Accessor for extracompilers
+ VCFilter &filterForExtraCompiler(const QString &compilerName);
+};
+
+// Tree & Flat view of files --------------------------------------------------
+class VCFilter;
+class Node
+{
+public:
+ virtual ~Node() { }
+ void addElement(const VCFilterFile &file) {
+ addElement(file.file, file);
+ }
+ virtual void addElement(const QString &filepath, const VCFilterFile &allInfo) = 0;
+ virtual void removeElements()= 0;
+ virtual void generateXML(XmlOutput &xml, const QString &tagName, VCProject &tool, const QString &filter) = 0;
+ virtual bool hasElements() = 0;
+};
+
+class TreeNode : public Node
+{
+ typedef QMap<QString, TreeNode*> ChildrenMap;
+ VCFilterFile info;
+ ChildrenMap children;
+
+public:
+ virtual ~TreeNode() { removeElements(); }
+
+ int pathIndex(const QString &filepath) {
+ int Windex = filepath.indexOf("\\");
+ int Uindex = filepath.indexOf("/");
+ if (Windex != -1 && Uindex != -1)
+ return qMin(Windex, Uindex);
+ else if (Windex != -1)
+ return Windex;
+ return Uindex;
+ }
+
+ void addElement(const QString &filepath, const VCFilterFile &allInfo){
+ QString newNodeName(filepath);
+
+ int index = pathIndex(filepath);
+ if (index != -1)
+ newNodeName = filepath.left(index);
+
+ TreeNode *n = children.value(newNodeName);
+ if (!n) {
+ n = new TreeNode;
+ n->info = allInfo;
+ children.insert(newNodeName, n);
+ }
+ if (index != -1)
+ n->addElement(filepath.mid(index+1), allInfo);
+ }
+
+ void removeElements() {
+ ChildrenMap::ConstIterator it = children.constBegin();
+ ChildrenMap::ConstIterator end = children.constEnd();
+ for( ; it != end; it++) {
+ (*it)->removeElements();
+ delete it.value();
+ }
+ children.clear();
+ }
+
+ void generateXML(XmlOutput &xml, const QString &tagName, VCProject &tool, const QString &filter);
+ bool hasElements() {
+ return children.size() != 0;
+ }
+};
+
+class FlatNode : public Node
+{
+ typedef QMap<QString, VCFilterFile> ChildrenMapFlat;
+ ChildrenMapFlat children;
+
+public:
+ virtual ~FlatNode() { removeElements(); }
+
+ int pathIndex(const QString &filepath) {
+ int Windex = filepath.lastIndexOf("\\");
+ int Uindex = filepath.lastIndexOf("/");
+ if (Windex != -1 && Uindex != -1)
+ return qMax(Windex, Uindex);
+ else if (Windex != -1)
+ return Windex;
+ return Uindex;
+ }
+
+ void addElement(const QString &filepath, const VCFilterFile &allInfo){
+ QString newKey(filepath);
+
+ int index = pathIndex(filepath);
+ if (index != -1)
+ newKey = filepath.mid(index+1);
+
+ // Key designed to sort files with same
+ // name in different paths correctly
+ children.insert(newKey + "\0" + allInfo.file, allInfo);
+ }
+
+ void removeElements() {
+ children.clear();
+ }
+
+ void generateXML(XmlOutput &xml, const QString &tagName, VCProject &proj, const QString &filter);
+ bool hasElements() {
+ return children.size() != 0;
+ }
+};
+// ----------------------------------------------------------------------------
+
+class VCProject
+{
+public:
+ // Variables
+ QString Name;
+ QString Version;
+ QString ProjectGUID;
+ QString Keyword;
+ QString SccProjectName;
+ QString SccLocalPath;
+ QString PlatformName;
+
+ // Single projects
+ QList<VCProjectSingleConfig> SingleProjects;
+
+ // List of all extracompilers
+ QStringList ExtraCompilers;
+};
+
+class VCProjectWriter
+{
+public:
+ virtual ~VCProjectWriter() {}
+
+ virtual void write(XmlOutput &, VCProjectSingleConfig &);
+ virtual void write(XmlOutput &, VCProject &);
+
+ virtual void write(XmlOutput &, const VCCLCompilerTool &);
+ virtual void write(XmlOutput &, const VCLinkerTool &);
+ virtual void write(XmlOutput &, const VCMIDLTool &);
+ virtual void write(XmlOutput &, const VCCustomBuildTool &);
+ virtual void write(XmlOutput &, const VCLibrarianTool &);
+ virtual void write(XmlOutput &, const VCResourceCompilerTool &);
+ virtual void write(XmlOutput &, const VCEventTool &);
+ virtual void write(XmlOutput &, const VCDeploymentTool &);
+ virtual void write(XmlOutput &, const VCConfiguration &);
+ virtual void write(XmlOutput &, VCFilter &);
+
+private:
+ static void outputFilter(VCProject &project, XmlOutput &xml, const QString &filtername);
+ static void outputFileConfigs(VCProject &project, XmlOutput &xml, const VCFilterFile &info, const QString &filtername);
+ static void outputFileConfig(VCFilter &filter, XmlOutput &xml, const QString &filename);
+
+ friend class TreeNode;
+ friend class FlatNode;
+};
+
+QT_END_NAMESPACE
+
+#endif // MSVC_OBJECTMODEL_H
diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp
new file mode 100644
index 0000000000..56f3bfdb94
--- /dev/null
+++ b/qmake/generators/win32/msvc_vcproj.cpp
@@ -0,0 +1,1569 @@
+/****************************************************************************
+**
+** 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 "msvc_vcproj.h"
+#include "option.h"
+#include "xmloutput.h"
+#include <qdir.h>
+#include <qdiriterator.h>
+#include <qcryptographichash.h>
+#include <qregexp.h>
+#include <qhash.h>
+#include <quuid.h>
+#include <stdlib.h>
+
+//#define DEBUG_SOLUTION_GEN
+
+QT_BEGIN_NAMESPACE
+// Filter GUIDs (Do NOT change these!) ------------------------------
+const char _GUIDSourceFiles[] = "{4FC737F1-C7A5-4376-A066-2A32D752A2FF}";
+const char _GUIDHeaderFiles[] = "{93995380-89BD-4b04-88EB-625FBE52EBFB}";
+const char _GUIDGeneratedFiles[] = "{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}";
+const char _GUIDResourceFiles[] = "{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}";
+const char _GUIDLexYaccFiles[] = "{E12AE0D2-192F-4d59-BD23-7D3FA58D3183}";
+const char _GUIDTranslationFiles[] = "{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}";
+const char _GUIDFormFiles[] = "{99349809-55BA-4b9d-BF79-8FDBB0286EB3}";
+const char _GUIDExtraCompilerFiles[] = "{E0D8C965-CC5F-43d7-AD63-FAEF0BBC0F85}";
+QT_END_NAMESPACE
+
+#ifdef Q_OS_WIN32
+#include <qt_windows.h>
+#include <windows/registry_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct {
+ DotNET version;
+ const char *versionStr;
+ const char *regKey;
+} dotNetCombo[] = {
+#ifdef Q_OS_WIN64
+ {NET2010, "MSVC.NET 2010 (10.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\10.0\\Setup\\VC\\ProductDir"},
+ {NET2010, "MSVC.NET 2010 Express Edition (10.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\10.0\\Setup\\VC\\ProductDir"},
+ {NET2008, "MSVC.NET 2008 (9.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\9.0\\Setup\\VC\\ProductDir"},
+ {NET2008, "MSVC.NET 2008 Express Edition (9.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\9.0\\Setup\\VC\\ProductDir"},
+ {NET2005, "MSVC.NET 2005 (8.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"},
+ {NET2005, "MSVC.NET 2005 Express Edition (8.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\8.0\\Setup\\VC\\ProductDir"},
+ {NET2003, "MSVC.NET 2003 (7.1)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\7.1\\Setup\\VC\\ProductDir"},
+ {NET2002, "MSVC.NET 2002 (7.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\7.0\\Setup\\VC\\ProductDir"},
+#else
+ {NET2010, "MSVC.NET 2010 (10.0)", "Software\\Microsoft\\VisualStudio\\10.0\\Setup\\VC\\ProductDir"},
+ {NET2010, "MSVC.NET 2010 Express Edition (10.0)", "Software\\Microsoft\\VCExpress\\10.0\\Setup\\VC\\ProductDir"},
+ {NET2008, "MSVC.NET 2008 (9.0)", "Software\\Microsoft\\VisualStudio\\9.0\\Setup\\VC\\ProductDir"},
+ {NET2008, "MSVC.NET 2008 Express Edition (9.0)", "Software\\Microsoft\\VCExpress\\9.0\\Setup\\VC\\ProductDir"},
+ {NET2005, "MSVC.NET 2005 (8.0)", "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"},
+ {NET2005, "MSVC.NET 2005 Express Edition (8.0)", "Software\\Microsoft\\VCExpress\\8.0\\Setup\\VC\\ProductDir"},
+ {NET2003, "MSVC.NET 2003 (7.1)", "Software\\Microsoft\\VisualStudio\\7.1\\Setup\\VC\\ProductDir"},
+ {NET2002, "MSVC.NET 2002 (7.0)", "Software\\Microsoft\\VisualStudio\\7.0\\Setup\\VC\\ProductDir"},
+#endif
+ {NETUnknown, "", ""},
+};
+
+QT_END_NAMESPACE
+#endif
+
+QT_BEGIN_NAMESPACE
+DotNET which_dotnet_version()
+{
+#ifndef Q_OS_WIN32
+ return NET2002; // Always generate 7.0 versions on other platforms
+#else
+ // Only search for the version once
+ static DotNET current_version = NETUnknown;
+ if(current_version != NETUnknown)
+ return current_version;
+
+ // Fallback to .NET 2002
+ current_version = NET2002;
+
+ QStringList warnPath;
+ int installed = 0;
+ int i = 0;
+ for(; dotNetCombo[i].version; ++i) {
+ QString path = qt_readRegistryKey(HKEY_LOCAL_MACHINE, dotNetCombo[i].regKey);
+ if(!path.isEmpty()) {
+ ++installed;
+ current_version = dotNetCombo[i].version;
+ warnPath += QString("%1").arg(dotNetCombo[i].versionStr);
+ }
+ }
+
+ if (installed < 2)
+ return current_version;
+
+ // More than one version installed, search directory path
+ QString paths = qgetenv("PATH");
+ QStringList pathlist = paths.toLower().split(";");
+
+ i = installed = 0;
+ for(; dotNetCombo[i].version; ++i) {
+ QString productPath = qt_readRegistryKey(HKEY_LOCAL_MACHINE, dotNetCombo[i].regKey).toLower();
+ if (productPath.isEmpty())
+ continue;
+ QStringList::iterator it;
+ for(it = pathlist.begin(); it != pathlist.end(); ++it) {
+ if((*it).contains(productPath)) {
+ ++installed;
+ current_version = dotNetCombo[i].version;
+ warnPath += QString("%1 in path").arg(dotNetCombo[i].versionStr);
+ break;
+ }
+ }
+ }
+ switch(installed) {
+ case 1:
+ break;
+ case 0:
+ warn_msg(WarnLogic, "Generator: MSVC.NET: Found more than one version of Visual Studio, but"
+ " none in your path! Fallback to lowest version (%s)", warnPath.join(", ").toLatin1().data());
+ break;
+ default:
+ warn_msg(WarnLogic, "Generator: MSVC.NET: Found more than one version of Visual Studio in"
+ " your path! Fallback to lowest version (%s)", warnPath.join(", ").toLatin1().data());
+ break;
+ }
+
+ return current_version;
+#endif
+};
+
+// Flatfile Tags ----------------------------------------------------
+const char _slnHeader70[] = "Microsoft Visual Studio Solution File, Format Version 7.00";
+const char _slnHeader71[] = "Microsoft Visual Studio Solution File, Format Version 8.00";
+const char _slnHeader80[] = "Microsoft Visual Studio Solution File, Format Version 9.00"
+ "\n# Visual Studio 2005";
+const char _slnHeader90[] = "Microsoft Visual Studio Solution File, Format Version 10.00"
+ "\n# Visual Studio 2008";
+const char _slnHeader100[] = "Microsoft Visual Studio Solution File, Format Version 11.00"
+ "\n# Visual Studio 2010";
+ // The following UUID _may_ change for later servicepacks...
+ // If so we need to search through the registry at
+ // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.0\Projects
+ // to find the subkey that contains a "PossibleProjectExtension"
+ // containing "vcproj"...
+ // Use the hardcoded value for now so projects generated on other
+ // platforms are actually usable.
+const char _slnMSVCvcprojGUID[] = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}";
+const char _slnProjectBeg[] = "\nProject(\"";
+const char _slnProjectMid[] = "\") = ";
+const char _slnProjectEnd[] = "\nEndProject";
+const char _slnGlobalBeg[] = "\nGlobal";
+const char _slnGlobalEnd[] = "\nEndGlobal";
+const char _slnSolutionConf[] = "\n\tGlobalSection(SolutionConfiguration) = preSolution"
+ "\n\t\tConfigName.0 = Debug|Win32"
+ "\n\t\tConfigName.1 = Release|Win32"
+ "\n\tEndGlobalSection";
+const char _slnProjDepBeg[] = "\n\tGlobalSection(ProjectDependencies) = postSolution";
+const char _slnProjDepEnd[] = "\n\tEndGlobalSection";
+const char _slnProjConfBeg[] = "\n\tGlobalSection(ProjectConfiguration) = postSolution";
+const char _slnProjRelConfTag1[]= ".Release|%1.ActiveCfg = Release|";
+const char _slnProjRelConfTag2[]= ".Release|%1.Build.0 = Release|";
+const char _slnProjDbgConfTag1[]= ".Debug|%1.ActiveCfg = Debug|";
+const char _slnProjDbgConfTag2[]= ".Debug|%1.Build.0 = Debug|";
+const char _slnProjConfEnd[] = "\n\tEndGlobalSection";
+const char _slnExtSections[] = "\n\tGlobalSection(ExtensibilityGlobals) = postSolution"
+ "\n\tEndGlobalSection"
+ "\n\tGlobalSection(ExtensibilityAddIns) = postSolution"
+ "\n\tEndGlobalSection";
+// ------------------------------------------------------------------
+
+VcprojGenerator::VcprojGenerator()
+ : Win32MakefileGenerator(),
+ init_flag(false),
+ projectWriter(0)
+{
+}
+
+VcprojGenerator::~VcprojGenerator()
+{
+ delete projectWriter;
+}
+
+bool VcprojGenerator::writeMakefile(QTextStream &t)
+{
+ initProject(); // Fills the whole project with proper data
+
+ // Generate solution file
+ if(project->first("TEMPLATE") == "vcsubdirs") {
+ if (!project->isActiveConfig("build_pass")) {
+ debug_msg(1, "Generator: MSVC.NET: Writing solution file");
+ writeSubDirs(t);
+ } else {
+ debug_msg(1, "Generator: MSVC.NET: Not writing solution file for build_pass configs");
+ }
+ return true;
+ } else
+ // Generate single configuration project file
+ if (project->first("TEMPLATE") == "vcapp" ||
+ project->first("TEMPLATE") == "vclib") {
+ if(!project->isActiveConfig("build_pass")) {
+ debug_msg(1, "Generator: MSVC.NET: Writing single configuration project file");
+ XmlOutput xmlOut(t);
+ projectWriter->write(xmlOut, vcProject);
+ }
+ return true;
+ }
+ return project->isActiveConfig("build_pass");
+}
+
+bool VcprojGenerator::writeProjectMakefile()
+{
+ usePlatformDir();
+ QTextStream t(&Option::output);
+
+ // Check if all requirements are fulfilled
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
+ var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
+ return true;
+ }
+
+ // Generate project file
+ if(project->first("TEMPLATE") == "vcapp" ||
+ project->first("TEMPLATE") == "vclib") {
+ if (!mergedProjects.count()) {
+ warn_msg(WarnLogic, "Generator: MSVC.NET: no single configuration created, cannot output project!");
+ return false;
+ }
+
+ debug_msg(1, "Generator: MSVC.NET: Writing project file");
+ VCProject mergedProject;
+ for (int i = 0; i < mergedProjects.count(); ++i) {
+ VCProjectSingleConfig *singleProject = &(mergedProjects.at(i)->vcProject);
+ mergedProject.SingleProjects += *singleProject;
+ for (int j = 0; j < singleProject->ExtraCompilersFiles.count(); ++j) {
+ const QString &compilerName = singleProject->ExtraCompilersFiles.at(j).Name;
+ if (!mergedProject.ExtraCompilers.contains(compilerName))
+ mergedProject.ExtraCompilers += compilerName;
+ }
+ }
+
+ if(mergedProjects.count() > 1 &&
+ mergedProjects.at(0)->vcProject.Name ==
+ mergedProjects.at(1)->vcProject.Name)
+ mergedProjects.at(0)->writePrlFile();
+ mergedProject.Name = project->first("QMAKE_PROJECT_NAME");
+ mergedProject.Version = mergedProjects.at(0)->vcProject.Version;
+ mergedProject.ProjectGUID = project->isEmpty("QMAKE_UUID") ? getProjectUUID().toString().toUpper() : project->first("QMAKE_UUID");
+ mergedProject.Keyword = project->first("VCPROJ_KEYWORD");
+ mergedProject.SccProjectName = mergedProjects.at(0)->vcProject.SccProjectName;
+ mergedProject.SccLocalPath = mergedProjects.at(0)->vcProject.SccLocalPath;
+ mergedProject.PlatformName = mergedProjects.at(0)->vcProject.PlatformName;
+
+ XmlOutput xmlOut(t);
+ projectWriter->write(xmlOut, mergedProject);
+ return true;
+ } else if(project->first("TEMPLATE") == "vcsubdirs") {
+ return writeMakefile(t);
+ }
+ return false;
+}
+
+struct VcsolutionDepend {
+ QString uuid;
+ QString vcprojFile, orig_target, target;
+ Target targetType;
+ QStringList dependencies;
+};
+
+QUuid VcprojGenerator::getProjectUUID(const QString &filename)
+{
+ bool validUUID = true;
+
+ // Read GUID from variable-space
+ QUuid uuid = project->first("GUID");
+
+ // If none, create one based on the MD5 of absolute project path
+ if(uuid.isNull() || !filename.isEmpty()) {
+ QString abspath = Option::fixPathToLocalOS(filename.isEmpty()?project->first("QMAKE_MAKEFILE"):filename);
+ QByteArray digest = QCryptographicHash::hash(abspath.toUtf8(), QCryptographicHash::Md5);
+ memcpy((unsigned char*)(&uuid), digest.constData(), sizeof(QUuid));
+ validUUID = !uuid.isNull();
+ uuid.data4[0] = (uuid.data4[0] & 0x3F) | 0x80; // UV_DCE variant
+ uuid.data3 = (uuid.data3 & 0x0FFF) | (QUuid::Name<<12);
+ }
+
+ // If still not valid, generate new one, and suggest adding to .pro
+ if(uuid.isNull() || !validUUID) {
+ uuid = QUuid::createUuid();
+ fprintf(stderr,
+ "qmake couldn't create a GUID based on filepath, and we couldn't\nfind a valid GUID in the .pro file (Consider adding\n'GUID = %s' to the .pro file)\n",
+ uuid.toString().toUpper().toLatin1().constData());
+ }
+
+ // Store GUID in variable-space
+ project->values("GUID") = QStringList(uuid.toString().toUpper());
+ return uuid;
+}
+
+QUuid VcprojGenerator::increaseUUID(const QUuid &id)
+{
+ QUuid result(id);
+ qint64 dataFirst = (result.data4[0] << 24) +
+ (result.data4[1] << 16) +
+ (result.data4[2] << 8) +
+ result.data4[3];
+ qint64 dataLast = (result.data4[4] << 24) +
+ (result.data4[5] << 16) +
+ (result.data4[6] << 8) +
+ result.data4[7];
+
+ if(!(dataLast++))
+ dataFirst++;
+
+ result.data4[0] = uchar((dataFirst >> 24) & 0xff);
+ result.data4[1] = uchar((dataFirst >> 16) & 0xff);
+ result.data4[2] = uchar((dataFirst >> 8) & 0xff);
+ result.data4[3] = uchar(dataFirst & 0xff);
+ result.data4[4] = uchar((dataLast >> 24) & 0xff);
+ result.data4[5] = uchar((dataLast >> 16) & 0xff);
+ result.data4[6] = uchar((dataLast >> 8) & 0xff);
+ result.data4[7] = uchar(dataLast & 0xff);
+ return result;
+}
+
+QStringList VcprojGenerator::collectSubDirs(QMakeProject *proj)
+{
+ QStringList subdirs;
+ QStringList tmp_proj_subdirs = proj->variables()["SUBDIRS"];
+ for(int x = 0; x < tmp_proj_subdirs.size(); ++x) {
+ QString tmpdir = tmp_proj_subdirs.at(x);
+ if(!proj->isEmpty(tmpdir + ".file")) {
+ if(!proj->isEmpty(tmpdir + ".subdir"))
+ warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s",
+ tmpdir.toLatin1().constData());
+ tmpdir = proj->first(tmpdir + ".file");
+ } else if(!proj->isEmpty(tmpdir + ".subdir")) {
+ tmpdir = proj->first(tmpdir + ".subdir");
+ }
+ subdirs += tmpdir;
+ }
+ return subdirs;
+}
+
+void VcprojGenerator::writeSubDirs(QTextStream &t)
+{
+ // Check if all requirements are fulfilled
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
+ var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
+ return;
+ }
+
+ switch(which_dotnet_version()) {
+ case NET2010:
+ t << _slnHeader100;
+ break;
+ case NET2008:
+ t << _slnHeader90;
+ break;
+ case NET2005:
+ t << _slnHeader80;
+ break;
+ case NET2003:
+ t << _slnHeader71;
+ break;
+ case NET2002:
+ t << _slnHeader70;
+ break;
+ default:
+ t << _slnHeader70;
+ warn_msg(WarnLogic, "Generator: MSVC.NET: Unknown version (%d) of MSVC detected for .sln", which_dotnet_version());
+ break;
+ }
+
+ QHash<QString, VcsolutionDepend*> solution_depends;
+ QList<VcsolutionDepend*> solution_cleanup;
+
+ QString oldpwd = qmake_getpwd();
+
+ // Make sure that all temp projects are configured
+ // for release so that the depends are created
+ // without the debug <lib>dxxx.lib name mangling
+ QStringList old_after_vars = Option::after_user_vars;
+ Option::after_user_vars.append("CONFIG+=release");
+
+ QStringList subdirs = collectSubDirs(project);
+ for(int i = 0; i < subdirs.size(); ++i) {
+ QString tmp = subdirs.at(i);
+ 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;
+ subdirs.append(profile);
+ } else {
+ 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)) {
+ // Check if all requirements are fulfilled
+ if(!tmp_proj.variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) {
+ fprintf(stderr, "Project file(%s) not added to Solution because all requirements not met:\n\t%s\n",
+ fn.toLatin1().constData(), tmp_proj.values("QMAKE_FAILED_REQUIREMENTS").join(" ").toLatin1().constData());
+ continue;
+ }
+ if(tmp_proj.first("TEMPLATE") == "vcsubdirs") {
+ foreach(const QString &tmpdir, collectSubDirs(&tmp_proj))
+ subdirs += fileFixify(tmpdir);
+ } else if(tmp_proj.first("TEMPLATE") == "vcapp" || tmp_proj.first("TEMPLATE") == "vclib") {
+ // Initialize a 'fake' project to get the correct variables
+ // and to be able to extract all the dependencies
+ Option::QMAKE_MODE old_mode = Option::qmake_mode;
+ Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING;
+ VcprojGenerator tmp_vcproj;
+ tmp_vcproj.setNoIO(true);
+ tmp_vcproj.setProjectFile(&tmp_proj);
+ Option::qmake_mode = old_mode;
+ 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());
+ }
+ }
+
+ // We assume project filename is [QMAKE_PROJECT_NAME].vcproj
+ QString vcproj = unescapeFilePath(tmp_vcproj.project->first("QMAKE_PROJECT_NAME") + project->first("VCPROJ_EXTENSION"));
+ QString vcprojDir = qmake_getpwd();
+
+ // If file doesn't exsist, then maybe the users configuration
+ // doesn't allow it to be created. Skip to next...
+ if(!exists(vcprojDir + Option::dir_sep + vcproj)) {
+
+ // Try to find the directory which fits relative
+ // to the output path, which represents the shadow
+ // path in case we are shadow building
+ QStringList list = fi.path().split(QLatin1Char('/'));
+ QString tmpDir = QFileInfo(Option::output).path() + Option::dir_sep;
+ bool found = false;
+ for (int i = list.size() - 1; i >= 0; --i) {
+ QString curr;
+ for (int j = i; j < list.size(); ++j)
+ curr += list.at(j) + Option::dir_sep;
+ if (exists(tmpDir + curr + vcproj)) {
+ vcprojDir = QDir::cleanPath(tmpDir + curr);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ warn_msg(WarnLogic, "Ignored (not found) '%s'", QString(vcprojDir + Option::dir_sep + vcproj).toLatin1().constData());
+ goto nextfile; // # Dirty!
+ }
+ }
+
+ VcsolutionDepend *newDep = new VcsolutionDepend;
+ newDep->vcprojFile = vcprojDir + Option::dir_sep + vcproj;
+ newDep->orig_target = unescapeFilePath(tmp_proj.first("QMAKE_ORIG_TARGET"));
+ newDep->target = tmp_proj.first("MSVCPROJ_TARGET").section(Option::dir_sep, -1);
+ newDep->targetType = tmp_vcproj.projectTarget;
+ newDep->uuid = tmp_proj.isEmpty("QMAKE_UUID") ? getProjectUUID(Option::fixPathToLocalOS(vcprojDir + QDir::separator() + vcproj)).toString().toUpper(): tmp_proj.first("QMAKE_UUID");
+
+ // We want to store it as the .lib name.
+ if(newDep->target.endsWith(".dll"))
+ newDep->target = newDep->target.left(newDep->target.length()-3) + "lib";
+
+ // All ActiveQt Server projects are dependent on idc.exe
+ if(tmp_proj.variables()["CONFIG"].contains("qaxserver"))
+ newDep->dependencies << "idc.exe";
+
+ // All extra compilers which has valid input are considered dependencies
+ const QStringList &quc = tmp_proj.variables()["QMAKE_EXTRA_COMPILERS"];
+ for(QStringList::ConstIterator it = quc.constBegin(); it != quc.constEnd(); ++it) {
+ const QStringList &invar = tmp_proj.variables().value((*it) + ".input");
+ for(QStringList::ConstIterator iit = invar.constBegin(); iit != invar.constEnd(); ++iit) {
+ const QStringList fileList = tmp_proj.variables().value(*iit);
+ if (!fileList.isEmpty()) {
+ const QStringList &cmdsParts = tmp_proj.variables().value((*it) + ".commands");
+ bool startOfLine = true;
+ foreach(QString cmd, cmdsParts) {
+ if (!startOfLine) {
+ if (cmd.contains("\r"))
+ startOfLine = true;
+ continue;
+ }
+ if (cmd.isEmpty())
+ continue;
+
+ startOfLine = false;
+ // Extra compiler commands might be defined in variables, so
+ // expand them (don't care about the in/out files)
+ cmd = tmp_vcproj.replaceExtraCompilerVariables(cmd, QStringList(), QStringList());
+ // Pull out command based on spaces and quoting, if the
+ // command starts with that
+ cmd = cmd.left(cmd.indexOf(cmd.at(0) == '"' ? '"' : ' ', 1));
+ QString dep = cmd.section('/', -1).section('\\', -1);
+ if (!newDep->dependencies.contains(dep))
+ newDep->dependencies << dep;
+ }
+ }
+ }
+ }
+
+ // Add all unknown libs to the deps
+ QStringList where = QStringList() << "QMAKE_LIBS" << "QMAKE_LIBS_PRIVATE";
+ if(!tmp_proj.isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ where = tmp_proj.variables()["QMAKE_INTERNAL_PRL_LIBS"];
+ for(QStringList::iterator wit = where.begin();
+ wit != where.end(); ++wit) {
+ QStringList &l = tmp_proj.variables()[(*wit)];
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString opt = (*it);
+ if(!opt.startsWith("/") && // Not a switch
+ opt != newDep->target && // Not self
+ opt != "opengl32.lib" && // We don't care about these libs
+ opt != "glu32.lib" && // to make depgen alittle faster
+ opt != "kernel32.lib" &&
+ opt != "user32.lib" &&
+ opt != "gdi32.lib" &&
+ opt != "comdlg32.lib" &&
+ opt != "advapi32.lib" &&
+ opt != "shell32.lib" &&
+ opt != "ole32.lib" &&
+ opt != "oleaut32.lib" &&
+ opt != "uuid.lib" &&
+ opt != "imm32.lib" &&
+ opt != "winmm.lib" &&
+ opt != "wsock32.lib" &&
+ opt != "ws2_32.lib" &&
+ opt != "winspool.lib" &&
+ opt != "delayimp.lib")
+ {
+ newDep->dependencies << opt.section(Option::dir_sep, -1);
+ }
+ }
+ }
+#ifdef DEBUG_SOLUTION_GEN
+ qDebug("Deps for %20s: [%s]", newDep->target.toLatin1().constData(), newDep->dependencies.join(" :: ").toLatin1().constData());
+#endif
+ solution_cleanup.append(newDep);
+ solution_depends.insert(newDep->target, newDep);
+ t << _slnProjectBeg << _slnMSVCvcprojGUID << _slnProjectMid
+ << "\"" << newDep->orig_target << "\", \"" << newDep->vcprojFile
+ << "\", \"" << newDep->uuid << "\"";
+ t << _slnProjectEnd;
+ }
+ }
+nextfile:
+ qmake_setpwd(oldpwd);
+ }
+ }
+ }
+ t << _slnGlobalBeg;
+ if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH")) {
+ QString slnConfCE = _slnSolutionConf;
+ QString platform = QString("|") + project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
+ slnConfCE.replace(QString("|Win32"), platform);
+ t << slnConfCE;
+ } else {
+ t << _slnSolutionConf;
+ }
+ t << _slnProjDepBeg;
+
+ // Restore previous after_user_var options
+ Option::after_user_vars = old_after_vars;
+
+ // Figure out dependencies
+ for(QList<VcsolutionDepend*>::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) {
+ int cnt = 0;
+ for(QStringList::iterator dit = (*it)->dependencies.begin(); dit != (*it)->dependencies.end(); ++dit) {
+ if(VcsolutionDepend *vc = solution_depends[*dit])
+ t << "\n\t\t" << (*it)->uuid << "." << cnt++ << " = " << vc->uuid;
+ }
+ }
+ t << _slnProjDepEnd;
+ t << _slnProjConfBeg;
+ for(QList<VcsolutionDepend*>::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) {
+ QString platform = "Win32";
+ if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"))
+ platform = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
+ t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag1).arg(platform) << platform;
+ t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag2).arg(platform) << platform;
+ t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag1).arg(platform) << platform;
+ t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag2).arg(platform) << platform;
+ }
+ t << _slnProjConfEnd;
+ t << _slnExtSections;
+ t << _slnGlobalEnd;
+
+
+ while (!solution_cleanup.isEmpty())
+ delete solution_cleanup.takeFirst();
+}
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+
+bool VcprojGenerator::hasBuiltinCompiler(const QString &file)
+{
+ // Source files
+ for (int i = 0; i < Option::cpp_ext.count(); ++i)
+ if (file.endsWith(Option::cpp_ext.at(i)))
+ return true;
+ for (int i = 0; i < Option::c_ext.count(); ++i)
+ if (file.endsWith(Option::c_ext.at(i)))
+ return true;
+ if (file.endsWith(".rc")
+ || file.endsWith(".idl"))
+ return true;
+ return false;
+}
+
+void VcprojGenerator::init()
+{
+ if (init_flag)
+ return;
+ init_flag = true;
+ projectWriter = createProjectWriter();
+
+ if(project->first("TEMPLATE") == "vcsubdirs") //too much work for subdirs
+ return;
+
+ debug_msg(1, "Generator: MSVC.NET: Initializing variables");
+
+ // this should probably not be here, but I'm using it to wrap the .t files
+ if (project->first("TEMPLATE") == "vcapp")
+ project->values("QMAKE_APP_FLAG").append("1");
+ else if (project->first("TEMPLATE") == "vclib")
+ project->values("QMAKE_LIB_FLAG").append("1");
+ if (project->values("QMAKESPEC").isEmpty())
+ project->values("QMAKESPEC").append(qgetenv("QMAKESPEC"));
+
+ processVars();
+
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
+ project->values("QMAKE_LIBS_PRIVATE") += escapeFilePaths(project->values("LIBS_PRIVATE"));
+
+ if(!project->values("VERSION").isEmpty()) {
+ QString version = project->values("VERSION")[0];
+ int firstDot = version.indexOf(".");
+ QString major = version.left(firstDot);
+ QString minor = version.right(version.length() - firstDot - 1);
+ minor.replace(QRegExp("\\."), "");
+ project->values("QMAKE_LFLAGS").append("/VERSION:" + major + "." + minor);
+ }
+
+ MakefileGenerator::init();
+ initOld(); // Currently calling old DSP code to set variables. CLEAN UP!
+
+ // Figure out what we're trying to build
+ if(project->first("TEMPLATE") == "vcapp") {
+ projectTarget = Application;
+ } else if(project->first("TEMPLATE") == "vclib") {
+ if(project->isActiveConfig("staticlib")) {
+ if (!project->values("RES_FILE").isEmpty())
+ project->values("MSVCPROJ_LIBS") += escapeFilePaths(project->values("RES_FILE"));
+ projectTarget = StaticLib;
+ } else
+ projectTarget = SharedLib;
+ }
+
+ // Setup PCH variables
+ precompH = project->first("PRECOMPILED_HEADER");
+ precompCPP = project->first("PRECOMPILED_SOURCE");
+ usePCH = !precompH.isEmpty() && project->isActiveConfig("precompile_header");
+ if (usePCH) {
+ precompHFilename = fileInfo(precompH).fileName();
+ // Created files
+ QString origTarget = unescapeFilePath(project->first("QMAKE_ORIG_TARGET"));
+ precompObj = origTarget + Option::obj_ext;
+ precompPch = origTarget + ".pch";
+ // Add PRECOMPILED_HEADER to HEADERS
+ if (!project->values("HEADERS").contains(precompH))
+ project->values("HEADERS") += precompH;
+ // Return to variable pool
+ project->values("PRECOMPILED_OBJECT") = QStringList(precompObj);
+ project->values("PRECOMPILED_PCH") = QStringList(precompPch);
+
+ autogenPrecompCPP = precompCPP.isEmpty() && project->isActiveConfig("autogen_precompile_source");
+ if (autogenPrecompCPP) {
+ precompCPP = precompH
+ + (Option::cpp_ext.count() ? Option::cpp_ext.at(0) : QLatin1String(".cpp"));
+ project->values("GENERATED_SOURCES") += precompCPP;
+ } else if (!precompCPP.isEmpty()) {
+ project->values("SOURCES") += precompCPP;
+ }
+ }
+
+ // Add all input files for a custom compiler into a map for uniqueness,
+ // unless the compiler is configure as a combined stage, then use the first one
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.constBegin(); it != quc.constEnd(); ++it) {
+ const QStringList &invar = project->variables().value((*it) + ".input");
+ const QString compiler_out = project->first((*it) + ".output");
+ for(QStringList::ConstIterator iit = invar.constBegin(); iit != invar.constEnd(); ++iit) {
+ QStringList fileList = project->variables().value(*iit);
+ if (!fileList.isEmpty()) {
+ if (project->values((*it) + ".CONFIG").indexOf("combine") != -1)
+ fileList = QStringList(fileList.first());
+ for(QStringList::ConstIterator fit = fileList.constBegin(); fit != fileList.constEnd(); ++fit) {
+ QString file = (*fit);
+ if (verifyExtraCompiler((*it), file)) {
+ if (!hasBuiltinCompiler(file)) {
+ extraCompilerSources[file] += *it;
+ } else {
+ QString out = Option::fixPathToTargetOS(replaceExtraCompilerVariables(
+ compiler_out, file, QString()), false);
+ extraCompilerSources[out] += *it;
+ extraCompilerOutputs[out] = QStringList(file); // Can only have one
+ }
+ }
+ }
+ }
+ }
+ }
+
+#if 0 // Debugging
+ Q_FOREACH(QString aKey, extraCompilerSources.keys()) {
+ qDebug("Extracompilers for %s are (%s)", aKey.toLatin1().constData(), extraCompilerSources.value(aKey).join(", ").toLatin1().constData());
+ }
+ Q_FOREACH(QString aKey, extraCompilerOutputs.keys()) {
+ qDebug("Object mapping for %s is (%s)", aKey.toLatin1().constData(), extraCompilerOutputs.value(aKey).join(", ").toLatin1().constData());
+ }
+ qDebug("");
+#endif
+}
+
+bool VcprojGenerator::mergeBuildProject(MakefileGenerator *other)
+{
+ if (!other || !other->projectFile()) {
+ warn_msg(WarnLogic, "VcprojGenerator: Cannot merge null project.");
+ return false;
+ }
+ if (other->projectFile()->first("MAKEFILE_GENERATOR") != project->first("MAKEFILE_GENERATOR")) {
+ warn_msg(WarnLogic, "VcprojGenerator: Cannot merge other types of projects! (ignored)");
+ return false;
+ }
+
+ VcprojGenerator *otherVC = static_cast<VcprojGenerator*>(other);
+ mergedProjects += otherVC;
+ return true;
+}
+
+void VcprojGenerator::initProject()
+{
+ // Initialize XML sub elements
+ // - Do this first since project elements may need
+ // - to know of certain configuration options
+ initConfiguration();
+ initRootFiles();
+ initSourceFiles();
+ initHeaderFiles();
+ initGeneratedFiles();
+ initLexYaccFiles();
+ initTranslationFiles();
+ initFormFiles();
+ initResourceFiles();
+ initExtraCompilerOutputs();
+
+ // Own elements -----------------------------
+ vcProject.Name = unescapeFilePath(project->first("QMAKE_ORIG_TARGET"));
+ switch(which_dotnet_version()) {
+ case NET2010:
+ vcProject.Version = "10.00";
+ break;
+ case NET2008:
+ vcProject.Version = "9,00";
+ break;
+ case NET2005:
+ //### using ',' because of a bug in 2005 B2
+ //### VS uses '.' or ',' depending on the regional settings! Using ',' always works.
+ vcProject.Version = "8,00";
+ break;
+ case NET2003:
+ vcProject.Version = "7.10";
+ break;
+ case NET2002:
+ vcProject.Version = "7.00";
+ break;
+ default:
+ vcProject.Version = "7.00";
+ warn_msg(WarnLogic, "Generator: MSVC.NET: Unknown version (%d) of MSVC detected for .vcproj", which_dotnet_version());
+ break;
+ }
+
+ vcProject.Keyword = project->first("VCPROJ_KEYWORD");
+ if (project->isEmpty("CE_SDK") || project->isEmpty("CE_ARCH")) {
+ vcProject.PlatformName = (vcProject.Configuration.idl.TargetEnvironment == midlTargetWin64 ? "Win64" : "Win32");
+ } else {
+ vcProject.PlatformName = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
+ }
+ // These are not used by Qt, but may be used by customers
+ vcProject.SccProjectName = project->first("SCCPROJECTNAME");
+ vcProject.SccLocalPath = project->first("SCCLOCALPATH");
+ vcProject.flat_files = project->isActiveConfig("flat");
+}
+
+void VcprojGenerator::initConfiguration()
+{
+ // Initialize XML sub elements
+ // - Do this first since main configuration elements may need
+ // - to know of certain compiler/linker options
+ VCConfiguration &conf = vcProject.Configuration;
+ conf.CompilerVersion = which_dotnet_version();
+
+ initCompilerTool();
+
+ // Only on configuration per build
+ bool isDebug = project->isActiveConfig("debug");
+
+ if(projectTarget == StaticLib)
+ initLibrarianTool();
+ else {
+ conf.linker.GenerateDebugInformation = isDebug ? _True : _False;
+ initLinkerTool();
+ }
+ initResourceTool();
+ initIDLTool();
+
+ // Own elements -----------------------------
+ QString temp = project->first("BuildBrowserInformation");
+ switch (projectTarget) {
+ case SharedLib:
+ conf.ConfigurationType = typeDynamicLibrary;
+ break;
+ case StaticLib:
+ conf.ConfigurationType = typeStaticLibrary;
+ break;
+ case Application:
+ default:
+ conf.ConfigurationType = typeApplication;
+ break;
+ }
+
+ conf.OutputDirectory = project->first("DESTDIR");
+ if (conf.OutputDirectory.isEmpty())
+ conf.OutputDirectory = ".\\";
+ if (!conf.OutputDirectory.endsWith("\\"))
+ conf.OutputDirectory += '\\';
+ if (conf.CompilerVersion >= NET2010) {
+ // The target name could have been changed.
+ conf.PrimaryOutput = project->first("TARGET");
+ if ( !conf.PrimaryOutput.isEmpty() && !project->first("TARGET_VERSION_EXT").isEmpty() && project->isActiveConfig("shared"))
+ conf.PrimaryOutput.append(project->first("TARGET_VERSION_EXT"));
+ }
+
+ conf.Name = project->values("BUILD_NAME").join(" ");
+ if (conf.Name.isEmpty())
+ conf.Name = isDebug ? "Debug" : "Release";
+ conf.ConfigurationName = conf.Name;
+ if (project->isEmpty("CE_SDK") || project->isEmpty("CE_ARCH")) {
+ conf.Name += (conf.idl.TargetEnvironment == midlTargetWin64 ? "|Win64" : "|Win32");
+ } else {
+ conf.Name += "|" + project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
+ }
+ conf.ATLMinimizesCRunTimeLibraryUsage = (project->first("ATLMinimizesCRunTimeLibraryUsage").isEmpty() ? _False : _True);
+ conf.BuildBrowserInformation = triState(temp.isEmpty() ? (short)unset : temp.toShort());
+ temp = project->first("CharacterSet");
+ conf.CharacterSet = charSet(temp.isEmpty() ? (short)charSetNotSet : temp.toShort());
+ conf.DeleteExtensionsOnClean = project->first("DeleteExtensionsOnClean");
+ conf.ImportLibrary = conf.linker.ImportLibrary;
+ conf.IntermediateDirectory = project->first("OBJECTS_DIR");
+ conf.WholeProgramOptimization = conf.compiler.WholeProgramOptimization;
+ temp = project->first("UseOfATL");
+ if(!temp.isEmpty())
+ conf.UseOfATL = useOfATL(temp.toShort());
+ temp = project->first("UseOfMfc");
+ if(!temp.isEmpty())
+ conf.UseOfMfc = useOfMfc(temp.toShort());
+
+ // Configuration does not need parameters from
+ // these sub XML items;
+ initCustomBuildTool();
+ initPreBuildEventTools();
+ initPostBuildEventTools();
+ // Only deploy for CE projects
+ if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"))
+ initDeploymentTool();
+ initPreLinkEventTools();
+
+ // Set definite values in both configurations
+ if (isDebug) {
+ conf.compiler.PreprocessorDefinitions.removeAll("NDEBUG");
+ } else {
+ conf.compiler.PreprocessorDefinitions += "NDEBUG";
+ }
+}
+
+void VcprojGenerator::initCompilerTool()
+{
+ QString placement = project->first("OBJECTS_DIR");
+ if(placement.isEmpty())
+ placement = ".\\";
+
+ VCConfiguration &conf = vcProject.Configuration;
+ conf.compiler.AssemblerListingLocation = placement ;
+ conf.compiler.ProgramDataBaseFileName = ".\\" ;
+ conf.compiler.ObjectFile = placement ;
+ conf.compiler.ExceptionHandling = ehNone;
+ // PCH
+ if (usePCH) {
+ conf.compiler.UsePrecompiledHeader = pchUseUsingSpecific;
+ conf.compiler.PrecompiledHeaderFile = "$(IntDir)\\" + precompPch;
+ conf.compiler.PrecompiledHeaderThrough = project->first("PRECOMPILED_HEADER");
+ conf.compiler.ForcedIncludeFiles = project->values("PRECOMPILED_HEADER");
+
+ if (conf.CompilerVersion <= NET2003) {
+ // Minimal build option triggers an Internal Compiler Error
+ // when used in conjunction with /FI and /Yu, so remove it
+ // ### work-around for a VS 2003 bug. Move to some prf file or remove completely.
+ project->values("QMAKE_CFLAGS_DEBUG").removeAll("-Gm");
+ project->values("QMAKE_CFLAGS_DEBUG").removeAll("/Gm");
+ project->values("QMAKE_CXXFLAGS_DEBUG").removeAll("-Gm");
+ project->values("QMAKE_CXXFLAGS_DEBUG").removeAll("/Gm");
+ }
+ }
+
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS"));
+
+ if (project->isActiveConfig("windows"))
+ conf.compiler.PreprocessorDefinitions += "_WINDOWS";
+ else if (project->isActiveConfig("console"))
+ conf.compiler.PreprocessorDefinitions += "_CONSOLE";
+
+ conf.compiler.PreprocessorDefinitions += project->values("DEFINES");
+ conf.compiler.PreprocessorDefinitions += project->values("PRL_EXPORT_DEFINES");
+ conf.compiler.parseOptions(project->values("MSVCPROJ_INCPATH"));
+}
+
+void VcprojGenerator::initLibrarianTool()
+{
+ VCConfiguration &conf = vcProject.Configuration;
+ conf.librarian.OutputFile = "$(OutDir)\\";
+ conf.librarian.OutputFile += project->first("MSVCPROJ_TARGET");
+ conf.librarian.AdditionalOptions += project->values("QMAKE_LIBFLAGS");
+}
+
+void VcprojGenerator::initLinkerTool()
+{
+ findLibraries(); // Need to add the highest version of the libs
+ VCConfiguration &conf = vcProject.Configuration;
+ conf.linker.parseOptions(project->values("QMAKE_LFLAGS"));
+
+ foreach (const QString &libDir, project->values("QMAKE_LIBDIR")) {
+ if (libDir.startsWith("/LIBPATH:"))
+ conf.linker.AdditionalLibraryDirectories += libDir.mid(9);
+ else
+ conf.linker.AdditionalLibraryDirectories += libDir;
+ }
+
+ if (!project->values("DEF_FILE").isEmpty())
+ conf.linker.ModuleDefinitionFile = project->first("DEF_FILE");
+
+ foreach(QString libs, project->values("MSVCPROJ_LIBS")) {
+ if (libs.left(9).toUpper() == "/LIBPATH:") {
+ QStringList l = QStringList(libs);
+ conf.linker.parseOptions(l);
+ } else {
+ conf.linker.AdditionalDependencies += libs;
+ }
+ }
+
+ conf.linker.OutputFile = "$(OutDir)\\";
+ conf.linker.OutputFile += project->first("MSVCPROJ_TARGET");
+
+ if(project->isActiveConfig("dll")){
+ conf.linker.parseOptions(project->values("QMAKE_LFLAGS_QT_DLL"));
+ }
+}
+
+void VcprojGenerator::initResourceTool()
+{
+ VCConfiguration &conf = vcProject.Configuration;
+ conf.resource.PreprocessorDefinitions = conf.compiler.PreprocessorDefinitions;
+
+ // We need to add _DEBUG for the debug version of the project, since the normal compiler defines
+ // do not contain it. (The compiler defines this symbol automatically, which is wy we don't need
+ // to add it for the compiler) However, the resource tool does not do this.
+ if(project->isActiveConfig("debug"))
+ conf.resource.PreprocessorDefinitions += "_DEBUG";
+ if(project->isActiveConfig("staticlib"))
+ conf.resource.ResourceOutputFileName = "$(OutDir)\\$(InputName).res";
+}
+
+void VcprojGenerator::initIDLTool()
+{
+}
+
+void VcprojGenerator::initCustomBuildTool()
+{
+}
+
+void VcprojGenerator::initPreBuildEventTools()
+{
+}
+
+void VcprojGenerator::initPostBuildEventTools()
+{
+ VCConfiguration &conf = vcProject.Configuration;
+ if (!project->values("QMAKE_POST_LINK").isEmpty()) {
+ QStringList cmdline = VCToolBase::fixCommandLine(var("QMAKE_POST_LINK"));
+ conf.postBuild.CommandLine = cmdline;
+ conf.postBuild.Description = cmdline.join(QLatin1String("\r\n"));
+ conf.postBuild.ExcludedFromBuild = _False;
+ }
+
+ QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE");
+ bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") &&
+ !project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH");
+ if (useSignature) {
+ conf.postBuild.CommandLine.prepend(
+ QLatin1String("signtool sign /F ") + signature + QLatin1String(" \"$(TargetPath)\""));
+ conf.postBuild.ExcludedFromBuild = _False;
+ }
+
+ if (!project->values("MSVCPROJ_COPY_DLL").isEmpty()) {
+ conf.postBuild.Description += var("MSVCPROJ_COPY_DLL_DESC");
+ conf.postBuild.CommandLine += var("MSVCPROJ_COPY_DLL");
+ conf.postBuild.ExcludedFromBuild = _False;
+ }
+}
+
+void VcprojGenerator::initDeploymentTool()
+{
+ VCConfiguration &conf = vcProject.Configuration;
+ QString targetPath = project->values("deploy.path").join(" ");
+ if (targetPath.isEmpty())
+ targetPath = QString("%CSIDL_PROGRAM_FILES%\\") + project->first("TARGET");
+ if (targetPath.endsWith("/") || targetPath.endsWith("\\"))
+ targetPath.chop(1);
+
+ // Only deploy Qt libs for shared build
+ if (!project->values("QMAKE_QT_DLL").isEmpty()) {
+ QStringList& arg = project->values("MSVCPROJ_LIBS");
+ for (QStringList::ConstIterator it = arg.constBegin(); it != arg.constEnd(); ++it) {
+ if (it->contains(project->first("QMAKE_LIBDIR"))) {
+ QString dllName = *it;
+
+ if (dllName.contains(QLatin1String("QAxContainer"))
+ || dllName.contains(QLatin1String("qtmain"))
+ || dllName.contains(QLatin1String("QtUiTools")))
+ continue;
+ dllName.replace(QLatin1String(".lib") , QLatin1String(".dll"));
+ QFileInfo info(dllName);
+ conf.deployment.AdditionalFiles += info.fileName()
+ + "|" + QDir::toNativeSeparators(info.absolutePath())
+ + "|" + targetPath
+ + "|0;";
+ }
+ }
+ }
+
+ // C-runtime deployment
+ QString runtime = project->values("QT_CE_C_RUNTIME").join(QLatin1String(" "));
+ if (!runtime.isEmpty() && (runtime != QLatin1String("no"))) {
+ QString runtimeVersion = QLatin1String("msvcr");
+ QString mkspec = project->first("QMAKESPEC");
+ // If no .qmake.cache has been found, we fallback to the original mkspec
+ if (mkspec.isEmpty())
+ mkspec = project->first("QMAKESPEC_ORIGINAL");
+
+ if (!mkspec.isEmpty()) {
+ if (mkspec.endsWith("2008"))
+ runtimeVersion.append("90");
+ else
+ runtimeVersion.append("80");
+ if (project->isActiveConfig("debug"))
+ runtimeVersion.append("d");
+ runtimeVersion.append(".dll");
+
+ if (runtime == "yes") {
+ // Auto-find C-runtime
+ QString vcInstallDir = qgetenv("VCINSTALLDIR");
+ if (!vcInstallDir.isEmpty()) {
+ vcInstallDir += "\\ce\\dll\\";
+ vcInstallDir += project->values("CE_ARCH").join(QLatin1String(" "));
+ if (!QFileInfo(vcInstallDir + QDir::separator() + runtimeVersion).exists())
+ runtime.clear();
+ else
+ runtime = vcInstallDir;
+ }
+ }
+ }
+
+ if (!runtime.isEmpty() && runtime != QLatin1String("yes")) {
+ conf.deployment.AdditionalFiles += runtimeVersion
+ + "|" + QDir::toNativeSeparators(runtime)
+ + "|" + targetPath
+ + "|0;";
+ }
+ }
+
+ // foreach item in DEPLOYMENT
+ foreach(QString item, project->values("DEPLOYMENT")) {
+ // get item.path
+ QString devicePath = project->first(item + ".path");
+ if (devicePath.isEmpty())
+ devicePath = targetPath;
+ // check if item.path is relative (! either /,\ or %)
+ if (!(devicePath.at(0) == QLatin1Char('/')
+ || devicePath.at(0) == QLatin1Char('\\')
+ || devicePath.at(0) == QLatin1Char('%'))) {
+ // create output path
+ devicePath = Option::fixPathToLocalOS(QDir::cleanPath(targetPath + QLatin1Char('\\') + devicePath));
+ }
+ // foreach d in item.sources
+ // ### Qt 5: remove .sources, inconsistent with INSTALLS
+ foreach(QString source, project->values(item + ".sources") + project->values(item + ".files")) {
+ QString itemDevicePath = devicePath;
+ source = Option::fixPathToLocalOS(source);
+ QString nameFilter;
+ QFileInfo info(source);
+ QString searchPath;
+ if (info.isDir()) {
+ nameFilter = QLatin1String("*");
+ itemDevicePath += "\\" + info.fileName();
+ searchPath = info.absoluteFilePath();
+ } else {
+ nameFilter = source.split('\\').last();
+ searchPath = info.absolutePath();
+ }
+
+ int pathSize = searchPath.size();
+ QDirIterator iterator(searchPath, QStringList() << nameFilter
+ , QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks
+ , QDirIterator::Subdirectories);
+ // foreach dirIterator-entry in d
+ while(iterator.hasNext()) {
+ iterator.next();
+ QString absoluteItemPath = Option::fixPathToLocalOS(QFileInfo(iterator.filePath()).absolutePath());
+ // Identify if it is just another subdir
+ int diffSize = absoluteItemPath.size() - pathSize;
+ // write out rules
+ conf.deployment.AdditionalFiles += iterator.fileName()
+ + "|" + absoluteItemPath
+ + "|" + itemDevicePath + (diffSize ? (absoluteItemPath.right(diffSize)) : QLatin1String(""))
+ + "|0;";
+ }
+ }
+ }
+}
+
+void VcprojGenerator::initPreLinkEventTools()
+{
+ VCConfiguration &conf = vcProject.Configuration;
+ if(!project->values("QMAKE_PRE_LINK").isEmpty()) {
+ QStringList cmdline = VCToolBase::fixCommandLine(var("QMAKE_PRE_LINK"));
+ conf.preLink.CommandLine = cmdline;
+ conf.preLink.Description = cmdline.join(QLatin1String("\r\n"));
+ conf.preLink.ExcludedFromBuild = _False;
+ }
+}
+
+void VcprojGenerator::initRootFiles()
+{
+ // Note: Root files do _not_ have any filter name, filter nor GUID!
+ vcProject.RootFiles.addFiles(project->values("RC_FILE"));
+
+ vcProject.RootFiles.Project = this;
+ vcProject.RootFiles.Config = &(vcProject.Configuration);
+ vcProject.RootFiles.CustomBuild = none;
+}
+
+void VcprojGenerator::initSourceFiles()
+{
+ vcProject.SourceFiles.Name = "Source Files";
+ vcProject.SourceFiles.Filter = "cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx";
+ vcProject.SourceFiles.Guid = _GUIDSourceFiles;
+
+ vcProject.SourceFiles.addFiles(project->values("SOURCES"));
+
+ vcProject.SourceFiles.Project = this;
+ vcProject.SourceFiles.Config = &(vcProject.Configuration);
+ vcProject.SourceFiles.CustomBuild = none;
+}
+
+void VcprojGenerator::initHeaderFiles()
+{
+ vcProject.HeaderFiles.Name = "Header Files";
+ vcProject.HeaderFiles.Filter = "h;hpp;hxx;hm;inl;inc;xsd";
+ vcProject.HeaderFiles.Guid = _GUIDHeaderFiles;
+
+ vcProject.HeaderFiles.addFiles(project->values("HEADERS"));
+ if (usePCH) // Generated PCH cpp file
+ vcProject.HeaderFiles.addFile(precompH);
+
+ vcProject.HeaderFiles.Project = this;
+ vcProject.HeaderFiles.Config = &(vcProject.Configuration);
+// vcProject.HeaderFiles.CustomBuild = mocHdr;
+// addMocArguments(vcProject.HeaderFiles);
+}
+
+void VcprojGenerator::initGeneratedFiles()
+{
+ vcProject.GeneratedFiles.Name = "Generated Files";
+ vcProject.GeneratedFiles.Filter = "cpp;c;cxx;moc;h;def;odl;idl;res;";
+ vcProject.GeneratedFiles.Guid = _GUIDGeneratedFiles;
+
+ // ### These cannot have CustomBuild (mocSrc)!!
+ vcProject.GeneratedFiles.addFiles(project->values("GENERATED_SOURCES"));
+ vcProject.GeneratedFiles.addFiles(project->values("GENERATED_FILES"));
+ vcProject.GeneratedFiles.addFiles(project->values("IDLSOURCES"));
+ vcProject.GeneratedFiles.addFiles(project->values("RES_FILE"));
+ vcProject.GeneratedFiles.addFiles(project->values("QMAKE_IMAGE_COLLECTION")); // compat
+ if(!extraCompilerOutputs.isEmpty())
+ vcProject.GeneratedFiles.addFiles(extraCompilerOutputs.keys());
+
+ vcProject.GeneratedFiles.Project = this;
+ vcProject.GeneratedFiles.Config = &(vcProject.Configuration);
+// vcProject.GeneratedFiles.CustomBuild = mocSrc;
+}
+
+void VcprojGenerator::initLexYaccFiles()
+{
+ vcProject.LexYaccFiles.Name = "Lex / Yacc Files";
+ vcProject.LexYaccFiles.ParseFiles = _False;
+ vcProject.LexYaccFiles.Filter = "l;y";
+ vcProject.LexYaccFiles.Guid = _GUIDLexYaccFiles;
+
+ vcProject.LexYaccFiles.addFiles(project->values("LEXSOURCES"));
+ vcProject.LexYaccFiles.addFiles(project->values("YACCSOURCES"));
+
+ vcProject.LexYaccFiles.Project = this;
+ vcProject.LexYaccFiles.Config = &(vcProject.Configuration);
+ vcProject.LexYaccFiles.CustomBuild = lexyacc;
+}
+
+void VcprojGenerator::initTranslationFiles()
+{
+ vcProject.TranslationFiles.Name = "Translation Files";
+ vcProject.TranslationFiles.ParseFiles = _False;
+ vcProject.TranslationFiles.Filter = "ts;xlf";
+ vcProject.TranslationFiles.Guid = _GUIDTranslationFiles;
+
+ vcProject.TranslationFiles.addFiles(project->values("TRANSLATIONS"));
+
+ vcProject.TranslationFiles.Project = this;
+ vcProject.TranslationFiles.Config = &(vcProject.Configuration);
+ vcProject.TranslationFiles.CustomBuild = none;
+}
+
+void VcprojGenerator::initFormFiles()
+{
+ vcProject.FormFiles.Name = "Form Files";
+ vcProject.FormFiles.ParseFiles = _False;
+ vcProject.FormFiles.Filter = "ui";
+ vcProject.FormFiles.Guid = _GUIDFormFiles;
+
+ vcProject.FormFiles.addFiles(project->values("FORMS"));
+ vcProject.FormFiles.addFiles(project->values("FORMS3"));
+
+ vcProject.FormFiles.Project = this;
+ vcProject.FormFiles.Config = &(vcProject.Configuration);
+ vcProject.FormFiles.CustomBuild = none;
+}
+
+void VcprojGenerator::initResourceFiles()
+{
+ vcProject.ResourceFiles.Name = "Resource Files";
+ vcProject.ResourceFiles.ParseFiles = _False;
+ vcProject.ResourceFiles.Filter = "qrc;*"; //"rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;ts;xlf;qrc";
+ vcProject.ResourceFiles.Guid = _GUIDResourceFiles;
+
+ // Bad hack, please look away -------------------------------------
+ QString rcc_dep_cmd = project->values("rcc.depend_command").join(" ");
+ if(!rcc_dep_cmd.isEmpty()) {
+ QStringList qrc_files = project->values("RESOURCES");
+ QStringList deps;
+ if(!qrc_files.isEmpty()) {
+ for (int i = 0; i < qrc_files.count(); ++i) {
+ char buff[256];
+ QString dep_cmd = replaceExtraCompilerVariables(rcc_dep_cmd, qrc_files.at(i),"");
+
+ dep_cmd = Option::fixPathToLocalOS(dep_cmd, true, false);
+ if(canExecute(dep_cmd)) {
+ dep_cmd.prepend(QLatin1String("cd ")
+ + escapeFilePath(Option::fixPathToLocalOS(Option::output_dir, false))
+ + QLatin1String(" && "));
+ 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())
+ deps += fileFixify(indeps.replace('\n', ' ').simplified().split(' '),
+ QString(), Option::output_dir);
+ }
+ }
+ }
+ vcProject.ResourceFiles.addFiles(deps);
+ }
+ }
+ // You may look again --------------------------------------------
+
+ vcProject.ResourceFiles.addFiles(project->values("RESOURCES"));
+ vcProject.ResourceFiles.addFiles(project->values("IMAGES"));
+
+ vcProject.ResourceFiles.Project = this;
+ vcProject.ResourceFiles.Config = &(vcProject.Configuration);
+ vcProject.ResourceFiles.CustomBuild = none;
+}
+
+void VcprojGenerator::initExtraCompilerOutputs()
+{
+ QStringList otherFilters;
+ otherFilters << "FORMS"
+ << "FORMS3"
+ << "GENERATED_FILES"
+ << "GENERATED_SOURCES"
+ << "HEADERS"
+ << "IDLSOURCES"
+ << "IMAGES"
+ << "LEXSOURCES"
+ << "QMAKE_IMAGE_COLLECTION"
+ << "RC_FILE"
+ << "RESOURCES"
+ << "RES_FILE"
+ << "SOURCES"
+ << "TRANSLATIONS"
+ << "YACCSOURCES";
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString extracompilerName = project->first((*it) + ".name");
+ if (extracompilerName.isEmpty())
+ extracompilerName = (*it);
+
+ // Create an extra compiler filter and add the files
+ VCFilter extraCompile;
+ extraCompile.Name = extracompilerName;
+ extraCompile.ParseFiles = _False;
+ extraCompile.Filter = "";
+ extraCompile.Guid = QString(_GUIDExtraCompilerFiles) + "-" + (*it);
+
+
+ // If the extra compiler has a variable_out set the output file
+ // is added to an other file list, and does not need its own..
+ bool addOnInput = hasBuiltinCompiler(project->first((*it) + ".output"));
+ QString tmp_other_out = project->first((*it) + ".variable_out");
+ if (!tmp_other_out.isEmpty() && !addOnInput)
+ continue;
+
+ if (!addOnInput) {
+ QString tmp_out = project->first((*it) + ".output");
+ if (project->values((*it) + ".CONFIG").indexOf("combine") != -1) {
+ // Combined output, only one file result
+ extraCompile.addFile(
+ Option::fixPathToTargetOS(replaceExtraCompilerVariables(tmp_out, QString(), QString()), false));
+ } else {
+ // One output file per input
+ QStringList tmp_in = project->values(project->first((*it) + ".input"));
+ for (int i = 0; i < tmp_in.count(); ++i) {
+ const QString &filename = tmp_in.at(i);
+ if (extraCompilerSources.contains(filename))
+ extraCompile.addFile(
+ Option::fixPathToTargetOS(replaceExtraCompilerVariables(filename, tmp_out, QString()), false));
+ }
+ }
+ } else {
+ // In this case we the outputs have a built-in compiler, so we cannot add the custom
+ // build steps there. So, we turn it around and add it to the input files instead,
+ // provided that the input file variable is not handled already (those in otherFilters
+ // are handled, so we avoid them).
+ QStringList inputVars = project->values((*it) + ".input");
+ foreach(QString inputVar, inputVars) {
+ if (!otherFilters.contains(inputVar)) {
+ QStringList tmp_in = project->values(inputVar);
+ for (int i = 0; i < tmp_in.count(); ++i) {
+ const QString &filename = tmp_in.at(i);
+ if (extraCompilerSources.contains(filename))
+ extraCompile.addFile(
+ Option::fixPathToTargetOS(replaceExtraCompilerVariables(filename, QString(), QString()), false));
+ }
+ }
+ }
+ }
+ extraCompile.Project = this;
+ extraCompile.Config = &(vcProject.Configuration);
+ extraCompile.CustomBuild = none;
+
+ vcProject.ExtraCompilersFiles.append(extraCompile);
+ }
+}
+
+void VcprojGenerator::initOld()
+{
+ // $$QMAKE.. -> $$MSVCPROJ.. -------------------------------------
+ project->values("MSVCPROJ_LIBS") += project->values("QMAKE_LIBS");
+ project->values("MSVCPROJ_LIBS") += project->values("QMAKE_LIBS_PRIVATE");
+ QStringList &incs = project->values("INCLUDEPATH");
+ for(QStringList::Iterator incit = incs.begin(); incit != incs.end(); ++incit) {
+ QString inc = (*incit);
+ if (!inc.startsWith('"') && !inc.endsWith('"'))
+ inc = QString("\"%1\"").arg(inc); // Quote all paths if not quoted already
+ project->values("MSVCPROJ_INCPATH").append("-I" + inc);
+ }
+ project->values("MSVCPROJ_INCPATH").append("-I" + specdir());
+
+ QString dest;
+ project->values("MSVCPROJ_TARGET") = QStringList(project->first("TARGET"));
+ Option::fixPathToTargetOS(project->first("TARGET"));
+ dest = project->first("TARGET") + project->first("TARGET_EXT");
+ project->values("MSVCPROJ_TARGET") = QStringList(dest);
+
+ // DLL COPY ------------------------------------------------------
+ if(project->isActiveConfig("dll") && !project->values("DLLDESTDIR").isEmpty()) {
+ QStringList dlldirs = project->values("DLLDESTDIR");
+ QString copydll("");
+ QStringList::Iterator dlldir;
+ for(dlldir = dlldirs.begin(); dlldir != dlldirs.end(); ++dlldir) {
+ if(!copydll.isEmpty())
+ copydll += " && ";
+ copydll += "copy \"$(TargetPath)\" \"" + *dlldir + "\"";
+ }
+
+ QString deststr("Copy " + dest + " to ");
+ for(dlldir = dlldirs.begin(); dlldir != dlldirs.end();) {
+ deststr += *dlldir;
+ ++dlldir;
+ if(dlldir != dlldirs.end())
+ deststr += ", ";
+ }
+
+ project->values("MSVCPROJ_COPY_DLL").append(copydll);
+ project->values("MSVCPROJ_COPY_DLL_DESC").append(deststr);
+ }
+
+ project->values("QMAKE_INTERNAL_PRL_LIBS") << "MSVCPROJ_LIBS";
+
+ // Verbose output if "-d -d"...
+ outputVariables();
+}
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+
+VCProjectWriter *VcprojGenerator::createProjectWriter()
+{
+ return new VCProjectWriter;
+}
+
+QString VcprojGenerator::replaceExtraCompilerVariables(const QString &var, const QStringList &in, const QStringList &out)
+{
+ QString ret = MakefileGenerator::replaceExtraCompilerVariables(var, in, out);
+
+ QStringList &defines = project->values("VCPROJ_MAKEFILE_DEFINES");
+ if(defines.isEmpty())
+ defines.append(varGlue("PRL_EXPORT_DEFINES"," -D"," -D","") +
+ varGlue("DEFINES"," -D"," -D",""));
+ ret.replace("$(DEFINES)", defines.first());
+
+ QStringList &incpath = project->values("VCPROJ_MAKEFILE_INCPATH");
+ if(incpath.isEmpty() && !this->var("MSVCPROJ_INCPATH").isEmpty())
+ incpath.append(this->var("MSVCPROJ_INCPATH"));
+ ret.replace("$(INCPATH)", incpath.join(" "));
+
+ return ret;
+}
+
+bool VcprojGenerator::openOutput(QFile &file, const QString &/*build*/) const
+{
+ QString outdir;
+ if(!file.fileName().isEmpty()) {
+ QFileInfo fi(fileInfo(file.fileName()));
+ if(fi.isDir())
+ outdir = file.fileName() + QDir::separator();
+ }
+ if(!outdir.isEmpty() || file.fileName().isEmpty()) {
+ QString ext = project->first("VCPROJ_EXTENSION");
+ if(project->first("TEMPLATE") == "vcsubdirs")
+ ext = project->first("VCSOLUTION_EXTENSION");
+ QString outputName = unescapeFilePath(project->first("TARGET"));
+ if (!project->first("MAKEFILE").isEmpty())
+ outputName = project->first("MAKEFILE");
+ file.setFileName(outdir + outputName + ext);
+ }
+ return Win32MakefileGenerator::openOutput(file, QString());
+}
+
+QString VcprojGenerator::fixFilename(QString ofile) const
+{
+ ofile = Option::fixPathToLocalOS(ofile);
+ int slashfind = ofile.lastIndexOf(Option::dir_sep);
+ if(slashfind == -1) {
+ ofile = ofile.replace('-', '_');
+ } else {
+ int hyphenfind = ofile.indexOf('-', slashfind);
+ while (hyphenfind != -1 && slashfind < hyphenfind) {
+ ofile = ofile.replace(hyphenfind, 1, '_');
+ hyphenfind = ofile.indexOf('-', hyphenfind + 1);
+ }
+ }
+ return ofile;
+}
+
+QString VcprojGenerator::findTemplate(QString file)
+{
+ QString ret;
+ if(!exists((ret = file)) &&
+ !exists((ret = QString(Option::mkfile::qmakespec + "/" + file))) &&
+ !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::DataPath) + "/win32-msvc.net/" + file))) &&
+ !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::DataPath) + "/win32-msvc2002/" + file))) &&
+ !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::DataPath) + "/win32-msvc2003/" + file))) &&
+ !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::DataPath) + "/win32-msvc2005/" + file))) &&
+ !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::DataPath) + "/win32-msvc2008/" + file))))
+ return "";
+ debug_msg(1, "Generator: MSVC.NET: Found template \'%s\'", ret.toLatin1().constData());
+ return ret;
+}
+
+void VcprojGenerator::outputVariables()
+{
+#if 0
+ qDebug("Generator: MSVC.NET: List of current variables:");
+ for(QMap<QString, QStringList>::ConstIterator it = project->variables().begin(); it != project->variables().end(); ++it)
+ qDebug("Generator: MSVC.NET: %s => %s", qPrintable(it.key()), qPrintable(it.value().join(" | ")));
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/msvc_vcproj.h b/qmake/generators/win32/msvc_vcproj.h
new file mode 100644
index 0000000000..afe8f9ff21
--- /dev/null
+++ b/qmake/generators/win32/msvc_vcproj.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** 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 MSVC_VCPROJ_H
+#define MSVC_VCPROJ_H
+
+#include "winmakefile.h"
+#include "msvc_objectmodel.h"
+
+QT_BEGIN_NAMESPACE
+
+enum Target {
+ Application,
+ SharedLib,
+ StaticLib
+};
+
+struct QUuid;
+class VcprojGenerator : public Win32MakefileGenerator
+{
+ bool init_flag;
+ bool writeVcprojParts(QTextStream &);
+
+ bool writeMakefile(QTextStream &);
+ bool writeProjectMakefile();
+
+ QString findTemplate(QString file);
+ void init();
+
+public:
+ VcprojGenerator();
+ ~VcprojGenerator();
+
+ QString defaultMakefile() const;
+ QString precompH, precompHFilename, precompCPP,
+ precompObj, precompPch;
+ bool autogenPrecompCPP;
+ static bool hasBuiltinCompiler(const QString &file);
+
+ QMap<QString, QStringList> extraCompilerSources;
+ QMap<QString, QStringList> extraCompilerOutputs;
+ bool usePCH;
+ VCProjectWriter *projectWriter;
+
+protected:
+ virtual VCProjectWriter *createProjectWriter();
+ virtual bool doDepends() const { return false; } //never necesary
+ virtual void processSources() { filterIncludedFiles("SOURCES"); filterIncludedFiles("GENERATED_SOURCES"); }
+ virtual QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &);
+ inline QString replaceExtraCompilerVariables(const QString &val, const QString &in, const QString &out)
+ { return MakefileGenerator::replaceExtraCompilerVariables(val, in, out); }
+ virtual bool supportsMetaBuild() { return true; }
+ virtual bool supportsMergedBuilds() { return true; }
+ virtual bool mergeBuildProject(MakefileGenerator *other);
+
+ virtual bool openOutput(QFile &file, const QString &build) const;
+ virtual bool findLibraries();
+ virtual void outputVariables();
+ QString fixFilename(QString ofile) const;
+
+ void initOld();
+ virtual void initProject();
+ void initConfiguration();
+ void initCompilerTool();
+ void initLinkerTool();
+ void initLibrarianTool();
+ void initResourceTool();
+ void initIDLTool();
+ void initCustomBuildTool();
+ void initPreBuildEventTools();
+ void initPostBuildEventTools();
+ void initDeploymentTool();
+ void initPreLinkEventTools();
+ void initRootFiles();
+ void initSourceFiles();
+ void initHeaderFiles();
+ void initGeneratedFiles();
+ void initTranslationFiles();
+ void initFormFiles();
+ void initResourceFiles();
+ void initLexYaccFiles();
+ void initExtraCompilerOutputs();
+
+ void writeSubDirs(QTextStream &t); // Called from VCXProj backend
+ QUuid getProjectUUID(const QString &filename=QString()); // Called from VCXProj backend
+
+ Target projectTarget;
+
+ // Used for single project
+ VCProjectSingleConfig vcProject;
+
+ // Holds all configurations for glue (merged) project
+ QList<VcprojGenerator*> mergedProjects;
+
+private:
+ QStringList collectSubDirs(QMakeProject *proj);
+ QUuid increaseUUID(const QUuid &id);
+ friend class VCFilter;
+};
+
+inline QString VcprojGenerator::defaultMakefile() const
+{
+ return project->first("TARGET") + project->first("VCPROJ_EXTENSION");
+}
+
+inline bool VcprojGenerator::findLibraries()
+{
+ return Win32MakefileGenerator::findLibraries("MSVCPROJ_LIBS");
+}
+
+QT_END_NAMESPACE
+
+#endif // MSVC_VCPROJ_H
diff --git a/qmake/generators/win32/msvc_vcxproj.cpp b/qmake/generators/win32/msvc_vcxproj.cpp
new file mode 100644
index 0000000000..1e7c4b7a93
--- /dev/null
+++ b/qmake/generators/win32/msvc_vcxproj.cpp
@@ -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 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 "msvc_vcxproj.h"
+#include "msbuild_objectmodel.h"
+#include <qdir.h>
+#include <qdiriterator.h>
+#include <quuid.h>
+
+
+QT_BEGIN_NAMESPACE
+// Filter GUIDs (Do NOT change these!) ------------------------------
+const char _GUIDSourceFiles[] = "{4FC737F1-C7A5-4376-A066-2A32D752A2FF}";
+const char _GUIDHeaderFiles[] = "{93995380-89BD-4b04-88EB-625FBE52EBFB}";
+const char _GUIDGeneratedFiles[] = "{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}";
+const char _GUIDResourceFiles[] = "{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}";
+const char _GUIDLexYaccFiles[] = "{E12AE0D2-192F-4d59-BD23-7D3FA58D3183}";
+const char _GUIDTranslationFiles[] = "{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}";
+const char _GUIDFormFiles[] = "{99349809-55BA-4b9d-BF79-8FDBB0286EB3}";
+const char _GUIDExtraCompilerFiles[] = "{E0D8C965-CC5F-43d7-AD63-FAEF0BBC0F85}";
+QT_END_NAMESPACE
+
+QT_BEGIN_NAMESPACE
+
+
+VcxprojGenerator::VcxprojGenerator() : VcprojGenerator()
+{
+}
+
+VCProjectWriter *VcxprojGenerator::createProjectWriter()
+{
+ return new VCXProjectWriter;
+}
+
+QT_END_NAMESPACE
+
diff --git a/qmake/generators/win32/msvc_vcxproj.h b/qmake/generators/win32/msvc_vcxproj.h
new file mode 100644
index 0000000000..3283cc7493
--- /dev/null
+++ b/qmake/generators/win32/msvc_vcxproj.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** 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 MSVC_VCXPROJ_H
+#define MSVC_VCXPROJ_H
+
+#include "winmakefile.h"
+#include "msbuild_objectmodel.h"
+#include "msvc_vcproj.h"
+
+QT_BEGIN_NAMESPACE
+
+class VcxprojGenerator : public VcprojGenerator
+{
+public:
+ VcxprojGenerator();
+ ~VcxprojGenerator();
+
+protected:
+ virtual VCProjectWriter *createProjectWriter();
+
+private:
+ friend class VCFilter;
+
+};
+
+inline VcxprojGenerator::~VcxprojGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // MSVC_VCXPROJ_H
diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp
new file mode 100644
index 0000000000..ef234ec506
--- /dev/null
+++ b/qmake/generators/win32/winmakefile.cpp
@@ -0,0 +1,895 @@
+/****************************************************************************
+**
+** 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 "winmakefile.h"
+#include "option.h"
+#include "project.h"
+#include "meta.h"
+#include <qtextstream.h>
+#include <qstring.h>
+#include <qhash.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <qdir.h>
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+Win32MakefileGenerator::Win32MakefileGenerator() : MakefileGenerator()
+{
+}
+
+int
+Win32MakefileGenerator::findHighestVersion(const QString &d, const QString &stem, const QString &ext)
+{
+ QString bd = Option::fixPathToLocalOS(d, true);
+ if(!exists(bd))
+ return -1;
+
+ QString dllStem = stem + QTDLL_POSTFIX;
+ QMakeMetaInfo libinfo;
+ bool libInfoRead = libinfo.readLib(bd + Option::dir_sep + dllStem);
+
+ // If the library, for which we're trying to find the highest version
+ // number, is a static library
+ if (libInfoRead && libinfo.values("QMAKE_PRL_CONFIG").contains("staticlib"))
+ return -1;
+
+ if(!project->values("QMAKE_" + stem.toUpper() + "_VERSION_OVERRIDE").isEmpty())
+ return project->values("QMAKE_" + stem.toUpper() + "_VERSION_OVERRIDE").first().toInt();
+
+ int biggest=-1;
+ if(!project->isActiveConfig("no_versionlink")) {
+ static QHash<QString, QStringList> dirEntryListCache;
+ QStringList entries = dirEntryListCache.value(bd);
+ if (entries.isEmpty()) {
+ QDir dir(bd);
+ entries = dir.entryList();
+ dirEntryListCache.insert(bd, entries);
+ }
+
+ QRegExp regx(QString("((lib)?%1([0-9]*)).(%2|prl)$").arg(dllStem).arg(ext), Qt::CaseInsensitive);
+ for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) {
+ if(regx.exactMatch((*it))) {
+ if (!regx.cap(3).isEmpty()) {
+ bool ok = true;
+ int num = regx.cap(3).toInt(&ok);
+ biggest = qMax(biggest, (!ok ? -1 : num));
+ }
+ }
+ }
+ }
+ if(libInfoRead
+ && !libinfo.values("QMAKE_PRL_CONFIG").contains("staticlib")
+ && !libinfo.isEmpty("QMAKE_PRL_VERSION"))
+ biggest = qMax(biggest, libinfo.first("QMAKE_PRL_VERSION").replace(".", "").toInt());
+ return biggest;
+}
+
+bool
+Win32MakefileGenerator::findLibraries(const QString &where)
+{
+ QStringList &l = project->values(where);
+ QList<QMakeLocalFileName> dirs;
+ {
+ QStringList &libpaths = project->values("QMAKE_LIBDIR");
+ for(QStringList::Iterator libpathit = libpaths.begin();
+ libpathit != libpaths.end(); ++libpathit)
+ dirs.append(QMakeLocalFileName((*libpathit)));
+ }
+ for(QStringList::Iterator it = l.begin(); it != l.end();) {
+ QChar quote;
+ bool modified_opt = false, remove = false;
+ QString opt = (*it).trimmed();
+ if((opt[0] == '\'' || opt[0] == '"') && opt[(int)opt.length()-1] == opt[0]) {
+ quote = opt[0];
+ opt = opt.mid(1, opt.length()-2);
+ }
+ if(opt.startsWith("/LIBPATH:")) {
+ dirs.append(QMakeLocalFileName(opt.mid(9)));
+ } else if(opt.startsWith("-L") || opt.startsWith("/L")) {
+ QString libpath = opt.mid(2);
+ QMakeLocalFileName l(libpath);
+ if(!dirs.contains(l)) {
+ dirs.append(l);
+ modified_opt = true;
+ if (!quote.isNull()) {
+ libpath = quote + libpath + quote;
+ quote = QChar();
+ }
+ (*it) = "/LIBPATH:" + libpath;
+ } else {
+ remove = true;
+ }
+ } else if(opt.startsWith("-l") || opt.startsWith("/l")) {
+ QString lib = opt.right(opt.length() - 2), out;
+ if(!lib.isEmpty()) {
+ QString suffix;
+ if(!project->isEmpty("QMAKE_" + lib.toUpper() + "_SUFFIX"))
+ suffix = project->first("QMAKE_" + lib.toUpper() + "_SUFFIX");
+ for(QList<QMakeLocalFileName>::Iterator it = dirs.begin();
+ it != dirs.end(); ++it) {
+ QString extension;
+ int ver = findHighestVersion((*it).local(), lib);
+ if(ver > 0)
+ extension += QString::number(ver);
+ extension += suffix;
+ extension += ".lib";
+ if(QMakeMetaInfo::libExists((*it).local() + Option::dir_sep + lib) ||
+ exists((*it).local() + Option::dir_sep + lib + extension)) {
+ out = (*it).real() + Option::dir_sep + lib + extension;
+ if (out.contains(QLatin1Char(' '))) {
+ out.prepend(QLatin1Char('\"'));
+ out.append(QLatin1Char('\"'));
+ }
+ break;
+ }
+ }
+ }
+ if(out.isEmpty())
+ out = lib + ".lib";
+ modified_opt = true;
+ (*it) = out;
+ } else if(!exists(Option::fixPathToLocalOS(opt))) {
+ QList<QMakeLocalFileName> lib_dirs;
+ QString file = opt;
+ int slsh = file.lastIndexOf(Option::dir_sep);
+ if(slsh != -1) {
+ lib_dirs.append(QMakeLocalFileName(file.left(slsh+1)));
+ file = file.right(file.length() - slsh - 1);
+ } else {
+ lib_dirs = dirs;
+ }
+ if(file.endsWith(".lib")) {
+ file = file.left(file.length() - 4);
+ if(!file.at(file.length()-1).isNumber()) {
+ QString suffix;
+ if(!project->isEmpty("QMAKE_" + file.section(Option::dir_sep, -1).toUpper() + "_SUFFIX"))
+ suffix = project->first("QMAKE_" + file.section(Option::dir_sep, -1).toUpper() + "_SUFFIX");
+ for(QList<QMakeLocalFileName>::Iterator dep_it = lib_dirs.begin(); dep_it != lib_dirs.end(); ++dep_it) {
+ QString lib_tmpl(file + "%1" + suffix + ".lib");
+ int ver = findHighestVersion((*dep_it).local(), file);
+ if(ver != -1) {
+ if(ver)
+ lib_tmpl = lib_tmpl.arg(ver);
+ else
+ lib_tmpl = lib_tmpl.arg("");
+ if(slsh != -1) {
+ QString dir = (*dep_it).real();
+ if(!dir.endsWith(Option::dir_sep))
+ dir += Option::dir_sep;
+ lib_tmpl.prepend(dir);
+ }
+ modified_opt = true;
+ (*it) = lib_tmpl;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if(remove) {
+ it = l.erase(it);
+ } else {
+ if(!quote.isNull() && modified_opt)
+ (*it) = quote + (*it) + quote;
+ ++it;
+ }
+ }
+ return true;
+}
+
+void
+Win32MakefileGenerator::processPrlFiles()
+{
+ QHash<QString, bool> processed;
+ QList<QMakeLocalFileName> libdirs;
+ {
+ QStringList &libpaths = project->values("QMAKE_LIBDIR");
+ for(QStringList::Iterator libpathit = libpaths.begin(); libpathit != libpaths.end(); ++libpathit)
+ libdirs.append(QMakeLocalFileName((*libpathit)));
+ }
+ 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 opt = (*it).trimmed();
+ if((opt[0] == '\'' || opt[0] == '"') && opt[(int)opt.length()-1] == opt[0])
+ opt = opt.mid(1, opt.length()-2);
+ if(opt.startsWith("/")) {
+ if(opt.startsWith("/LIBPATH:")) {
+ QMakeLocalFileName l(opt.mid(9));
+ if(!libdirs.contains(l))
+ libdirs.append(l);
+ }
+ } else if(!processed.contains(opt)) {
+ if(processPrlFile(opt)) {
+ processed.insert(opt, true);
+ ret = true;
+ } else if(QDir::isRelativePath(opt) || opt.startsWith("-l")) {
+ QString tmp;
+ if (opt.startsWith("-l"))
+ tmp = opt.mid(2);
+ else
+ tmp = opt;
+ for(QList<QMakeLocalFileName>::Iterator it = libdirs.begin(); it != libdirs.end(); ++it) {
+ QString prl = (*it).local() + Option::dir_sep + tmp;
+ // the original is used as the key
+ QString orgprl = prl;
+ if(processed.contains(prl)) {
+ break;
+ } else if(processPrlFile(prl)) {
+ processed.insert(orgprl, true);
+ ret = true;
+ break;
+ }
+ }
+ }
+ }
+ if(!opt.isEmpty())
+ l_out.append(opt);
+ }
+ if(ret)
+ l = l_out;
+ else
+ break;
+ }
+}
+
+
+void Win32MakefileGenerator::processVars()
+{
+ //If the TARGET looks like a path split it into DESTDIR and the resulting TARGET
+ if(!project->isEmpty("TARGET")) {
+ QString targ = 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");
+ if (project->isEmpty("QMAKE_PROJECT_NAME"))
+ project->values("QMAKE_PROJECT_NAME") = project->values("QMAKE_ORIG_TARGET");
+ else if (project->first("TEMPLATE").startsWith("vc"))
+ project->values("MAKEFILE") = project->values("QMAKE_PROJECT_NAME");
+
+ if (!project->values("QMAKE_INCDIR").isEmpty())
+ project->values("INCLUDEPATH") += project->values("QMAKE_INCDIR");
+
+ if (!project->values("VERSION").isEmpty()) {
+ QStringList l = project->first("VERSION").split('.');
+ if (l.size() > 0)
+ project->values("VER_MAJ").append(l[0]);
+ if (l.size() > 1)
+ project->values("VER_MIN").append(l[1]);
+ }
+
+ // TARGET_VERSION_EXT will be used to add a version number onto the target name
+ if (project->values("TARGET_VERSION_EXT").isEmpty()
+ && !project->values("VER_MAJ").isEmpty()
+ && project->values("QMAKE_SYMBIAN_SHLIB").isEmpty())
+ project->values("TARGET_VERSION_EXT").append(project->values("VER_MAJ").first());
+
+ if(project->isEmpty("QMAKE_COPY_FILE"))
+ project->values("QMAKE_COPY_FILE").append("$(COPY)");
+ if(project->isEmpty("QMAKE_COPY_DIR"))
+ project->values("QMAKE_COPY_DIR").append("xcopy /s /q /y /i");
+ if(project->isEmpty("QMAKE_INSTALL_FILE"))
+ project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
+ project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_DIR"))
+ project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
+
+ fixTargetExt();
+ processRcFileVar();
+ processFileTagsVar();
+
+ QStringList &incDir = project->values("INCLUDEPATH");
+ for(QStringList::Iterator incDir_it = incDir.begin(); incDir_it != incDir.end(); ++incDir_it) {
+ if(!(*incDir_it).isEmpty())
+ (*incDir_it) = Option::fixPathToTargetOS((*incDir_it), false, false);
+ }
+ QStringList &libDir = project->values("QMAKE_LIBDIR");
+ for(QStringList::Iterator libDir_it = libDir.begin(); libDir_it != libDir.end(); ++libDir_it) {
+ if(!(*libDir_it).isEmpty())
+ (*libDir_it) = Option::fixPathToTargetOS((*libDir_it), false, false);
+ }
+
+ if (project->values("TEMPLATE").contains("app")) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_APP");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_APP");
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_APP");
+ } else if (project->values("TEMPLATE").contains("lib") && project->isActiveConfig("dll")) {
+ if(!project->isActiveConfig("plugin") || !project->isActiveConfig("plugin_no_share_shlib_cflags")) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_SHLIB");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_SHLIB");
+ }
+ if (project->isActiveConfig("plugin")) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_PLUGIN");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_PLUGIN");
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PLUGIN");
+ } else {
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SHLIB");
+ }
+ }
+}
+
+void Win32MakefileGenerator::fixTargetExt()
+{
+ if (project->isEmpty("QMAKE_EXTENSION_STATICLIB"))
+ project->values("QMAKE_EXTENSION_STATICLIB").append("lib");
+ if (project->isEmpty("QMAKE_EXTENSION_SHLIB"))
+ project->values("QMAKE_EXTENSION_SHLIB").append("dll");
+
+ if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ project->values("TARGET_EXT").append(".exe");
+ } else if (project->isActiveConfig("shared")) {
+ project->values("TARGET_EXT").append(project->first("TARGET_VERSION_EXT") + "."
+ + project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET").first() = project->first("QMAKE_PREFIX_SHLIB") + project->first("TARGET");
+ } else {
+ project->values("TARGET_EXT").append("." + project->first("QMAKE_EXTENSION_STATICLIB"));
+ project->values("TARGET").first() = project->first("QMAKE_PREFIX_STATICLIB") + project->first("TARGET");
+ }
+}
+
+void Win32MakefileGenerator::processRcFileVar()
+{
+ if (Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
+ return;
+
+ if (((!project->values("VERSION").isEmpty())
+ && project->values("RC_FILE").isEmpty()
+ && project->values("RES_FILE").isEmpty()
+ && !project->isActiveConfig("no_generated_target_info")
+ && (project->isActiveConfig("shared") || !project->values("QMAKE_APP_FLAG").isEmpty()))
+ || !project->values("QMAKE_WRITE_DEFAULT_RC").isEmpty()){
+
+ QByteArray rcString;
+ QTextStream ts(&rcString, QFile::WriteOnly);
+
+ QStringList vers = project->values("VERSION").first().split(".");
+ for (int i = vers.size(); i < 4; i++)
+ vers += "0";
+ QString versionString = vers.join(".");
+
+ QString companyName;
+ if (!project->values("QMAKE_TARGET_COMPANY").isEmpty())
+ companyName = project->values("QMAKE_TARGET_COMPANY").join(" ");
+
+ QString description;
+ if (!project->values("QMAKE_TARGET_DESCRIPTION").isEmpty())
+ description = project->values("QMAKE_TARGET_DESCRIPTION").join(" ");
+
+ QString copyright;
+ if (!project->values("QMAKE_TARGET_COPYRIGHT").isEmpty())
+ copyright = project->values("QMAKE_TARGET_COPYRIGHT").join(" ");
+
+ QString productName;
+ if (!project->values("QMAKE_TARGET_PRODUCT").isEmpty())
+ productName = project->values("QMAKE_TARGET_PRODUCT").join(" ");
+ else
+ productName = project->values("TARGET").first();
+
+ QString originalName = project->values("TARGET").first() + project->values("TARGET_EXT").first();
+
+ ts << "# if defined(UNDER_CE)" << endl;
+ ts << "# include <winbase.h>" << endl;
+ ts << "# else" << endl;
+ ts << "# include <winver.h>" << endl;
+ ts << "# endif" << endl;
+ ts << endl;
+ ts << "VS_VERSION_INFO VERSIONINFO" << endl;
+ ts << "\tFILEVERSION " << QString(versionString).replace(".", ",") << endl;
+ ts << "\tPRODUCTVERSION " << QString(versionString).replace(".", ",") << endl;
+ ts << "\tFILEFLAGSMASK 0x3fL" << endl;
+ ts << "#ifdef _DEBUG" << endl;
+ ts << "\tFILEFLAGS VS_FF_DEBUG" << endl;
+ ts << "#else" << endl;
+ ts << "\tFILEFLAGS 0x0L" << endl;
+ ts << "#endif" << endl;
+ ts << "\tFILEOS VOS__WINDOWS32" << endl;
+ if (project->isActiveConfig("shared"))
+ ts << "\tFILETYPE VFT_DLL" << endl;
+ else
+ ts << "\tFILETYPE VFT_APP" << endl;
+ ts << "\tFILESUBTYPE 0x0L" << endl;
+ ts << "\tBEGIN" << endl;
+ ts << "\t\tBLOCK \"StringFileInfo\"" << endl;
+ ts << "\t\tBEGIN" << endl;
+ ts << "\t\t\tBLOCK \"040904B0\"" << endl;
+ ts << "\t\t\tBEGIN" << endl;
+ ts << "\t\t\t\tVALUE \"CompanyName\", \"" << companyName << "\\0\"" << endl;
+ ts << "\t\t\t\tVALUE \"FileDescription\", \"" << description << "\\0\"" << endl;
+ ts << "\t\t\t\tVALUE \"FileVersion\", \"" << versionString << "\\0\"" << endl;
+ ts << "\t\t\t\tVALUE \"LegalCopyright\", \"" << copyright << "\\0\"" << endl;
+ ts << "\t\t\t\tVALUE \"OriginalFilename\", \"" << originalName << "\\0\"" << endl;
+ ts << "\t\t\t\tVALUE \"ProductName\", \"" << productName << "\\0\"" << endl;
+ ts << "\t\t\tEND" << endl;
+ ts << "\t\tEND" << endl;
+ ts << "\t\tBLOCK \"VarFileInfo\"" << endl;
+ ts << "\t\tBEGIN" << endl;
+ ts << "\t\t\tVALUE \"Translation\", 0x409, 1200" << endl;
+ ts << "\t\tEND" << endl;
+ ts << "\tEND" << endl;
+ ts << "/* End of Version info */" << endl;
+ ts << endl;
+
+ ts.flush();
+
+
+ QString rcFilename = project->values("OUT_PWD").first()
+ + "/"
+ + project->values("TARGET").first()
+ + "_resource"
+ + ".rc";
+ QFile rcFile(QDir::cleanPath(rcFilename));
+
+ bool writeRcFile = true;
+ if (rcFile.exists() && rcFile.open(QFile::ReadOnly)) {
+ writeRcFile = rcFile.readAll() != rcString;
+ rcFile.close();
+ }
+ if (writeRcFile) {
+ bool ok;
+ ok = rcFile.open(QFile::WriteOnly);
+ if (!ok) {
+ // The file can't be opened... try creating the containing
+ // directory first (needed for clean shadow builds)
+ QDir().mkpath(QFileInfo(rcFile).path());
+ ok = rcFile.open(QFile::WriteOnly);
+ }
+ if (!ok) {
+ ::fprintf(stderr, "Cannot open for writing: %s", rcFile.fileName().toLatin1().constData());
+ ::exit(1);
+ }
+ rcFile.write(rcString);
+ rcFile.close();
+ }
+ if (project->values("QMAKE_WRITE_DEFAULT_RC").isEmpty())
+ project->values("RC_FILE").insert(0, rcFile.fileName());
+ }
+ if (!project->values("RC_FILE").isEmpty()) {
+ if (!project->values("RES_FILE").isEmpty()) {
+ fprintf(stderr, "Both rc and res file specified.\n");
+ fprintf(stderr, "Please specify one of them, not both.");
+ exit(1);
+ }
+ QString resFile = project->values("RC_FILE").first();
+
+ // if this is a shadow build then use the absolute path of the rc file
+ if (Option::output_dir != qmake_getpwd()) {
+ QFileInfo fi(resFile);
+ project->values("RC_FILE").first() = fi.absoluteFilePath();
+ }
+
+ resFile.replace(".rc", Option::res_ext);
+ project->values("RES_FILE").prepend(fileInfo(resFile).fileName());
+ if (!project->values("OBJECTS_DIR").isEmpty()) {
+ QString resDestDir;
+ if (project->isActiveConfig("staticlib"))
+ resDestDir = fileInfo(project->first("DESTDIR")).absoluteFilePath();
+ else
+ resDestDir = project->first("OBJECTS_DIR");
+ resDestDir.append(Option::dir_sep);
+ project->values("RES_FILE").first().prepend(resDestDir);
+ }
+ project->values("RES_FILE").first() = Option::fixPathToTargetOS(project->values("RES_FILE").first(), false, false);
+ project->values("POST_TARGETDEPS") += project->values("RES_FILE");
+ project->values("CLEAN_FILES") += project->values("RES_FILE");
+ }
+}
+
+void Win32MakefileGenerator::processFileTagsVar()
+{
+ QStringList tags;
+ tags << "SOURCES" << "GENERATED_SOURCES" << "DEF_FILE" << "RC_FILE"
+ << "TARGET" << "QMAKE_LIBS" << "DESTDIR" << "DLLDESTDIR" << "INCLUDEPATH";
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it)
+ tags += project->values((*it)+".input");
+ }
+
+ //clean path
+ QStringList &filetags = project->values("QMAKE_FILETAGS");
+ for(int i = 0; i < tags.size(); ++i)
+ filetags += Option::fixPathToTargetOS(tags.at(i), false);
+}
+
+void Win32MakefileGenerator::writeCleanParts(QTextStream &t)
+{
+ t << "clean: compiler_clean " << var("CLEAN_DEPS");
+ {
+ const char *clean_targets[] = { "OBJECTS", "QMAKE_CLEAN", "CLEAN_FILES", 0 };
+ for(int i = 0; clean_targets[i]; ++i) {
+ const QStringList &list = project->values(clean_targets[i]);
+ const QString del_statement("-$(DEL_FILE)");
+ if(project->isActiveConfig("no_delete_multiple_files")) {
+ for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
+ t << "\n\t" << del_statement << " " << escapeFilePath((*it));
+ } else {
+ QString files, file;
+ const int commandlineLimit = 2047; // NT limit, expanded
+ for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ file = " " + escapeFilePath((*it));
+ if(del_statement.length() + files.length() +
+ qMax(fixEnvVariables(file).length(), file.length()) > commandlineLimit) {
+ t << "\n\t" << del_statement << files;
+ files.clear();
+ }
+ files += file;
+ }
+ if(!files.isEmpty())
+ t << "\n\t" << del_statement << files;
+ }
+ }
+ }
+ t << endl << endl;
+
+ t << "distclean: clean";
+ {
+ const char *clean_targets[] = { "QMAKE_DISTCLEAN", 0 };
+ for(int i = 0; clean_targets[i]; ++i) {
+ const QStringList &list = project->values(clean_targets[i]);
+ const QString del_statement("-$(DEL_FILE)");
+ if(project->isActiveConfig("no_delete_multiple_files")) {
+ for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
+ t << "\n\t" << del_statement << " " << escapeFilePath((*it));
+ } else {
+ QString files, file;
+ const int commandlineLimit = 2047; // NT limit, expanded
+ for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ file = " " + escapeFilePath((*it));
+ if(del_statement.length() + files.length() +
+ qMax(fixEnvVariables(file).length(), file.length()) > commandlineLimit) {
+ t << "\n\t" << del_statement << files;
+ files.clear();
+ }
+ files += file;
+ }
+ if(!files.isEmpty())
+ t << "\n\t" << del_statement << files;
+ }
+ }
+ }
+ t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET)" << endl;
+ {
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(!ofile.isEmpty())
+ t << "\t-$(DEL_FILE) " << ofile << endl;
+ }
+ t << endl;
+}
+
+void Win32MakefileGenerator::writeIncPart(QTextStream &t)
+{
+ t << "INCPATH = ";
+
+ const QStringList &incs = project->values("INCLUDEPATH");
+ for(int i = 0; i < incs.size(); ++i) {
+ QString inc = incs.at(i);
+ inc.replace(QRegExp("\\\\$"), "");
+ inc.replace(QRegExp("\""), "");
+ if(!inc.isEmpty())
+ t << "-I" << "\"" << inc << "\" ";
+ }
+ t << "-I\"" << specdir() << "\""
+ << endl;
+}
+
+void Win32MakefileGenerator::writeStandardParts(QTextStream &t)
+{
+ t << "####### Compiler, tools and options" << endl << endl;
+ t << "CC = " << var("QMAKE_CC") << endl;
+ t << "CXX = " << var("QMAKE_CXX") << endl;
+ t << "DEFINES = "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << varGlue("DEFINES","-D"," -D","") << endl;
+ t << "CFLAGS = " << var("QMAKE_CFLAGS") << " $(DEFINES)" << endl;
+ t << "CXXFLAGS = " << var("QMAKE_CXXFLAGS") << " $(DEFINES)" << endl;
+
+ writeIncPart(t);
+ writeLibsPart(t);
+
+ t << "QMAKE = " << var("QMAKE_QMAKE") << endl;
+ t << "IDC = " << (project->isEmpty("QMAKE_IDC") ? QString("idc") :
+ Option::fixPathToTargetOS(var("QMAKE_IDC"), false)) << endl;
+ t << "IDL = " << (project->isEmpty("QMAKE_IDL") ? QString("midl") :
+ Option::fixPathToTargetOS(var("QMAKE_IDL"), false)) << endl;
+ t << "ZIP = " << var("QMAKE_ZIP") << endl;
+ t << "DEF_FILE = " << varList("DEF_FILE") << endl;
+ t << "RES_FILE = " << varList("RES_FILE") << endl; // Not on mingw, can't see why not though...
+ t << "COPY = " << var("QMAKE_COPY") << endl;
+ t << "COPY_FILE = " << var("QMAKE_COPY_FILE") << endl;
+ t << "COPY_DIR = " << var("QMAKE_COPY_DIR") << endl;
+ t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << 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 << "INSTALL_FILE = " << var("QMAKE_INSTALL_FILE") << endl;
+ t << "INSTALL_PROGRAM = " << var("QMAKE_INSTALL_PROGRAM") << endl;
+ t << "INSTALL_DIR = " << var("QMAKE_INSTALL_DIR") << endl;
+ t << endl;
+
+ t << "####### Output directory" << endl << endl;
+ if(!project->values("OBJECTS_DIR").isEmpty())
+ t << "OBJECTS_DIR = " << var("OBJECTS_DIR").replace(QRegExp("\\\\$"),"") << endl;
+ else
+ t << "OBJECTS_DIR = . " << endl;
+ t << endl;
+
+ t << "####### Files" << endl << endl;
+ t << "SOURCES = " << valList(escapeFilePaths(project->values("SOURCES")))
+ << " " << valList(escapeFilePaths(project->values("GENERATED_SOURCES"))) << endl;
+
+ // do this here so we can set DEST_TARGET to be the complete path to the final target if it is needed.
+ QString orgDestDir = var("DESTDIR");
+ QString destDir = Option::fixPathToTargetOS(orgDestDir, false);
+ if (!destDir.isEmpty() && (orgDestDir.endsWith('/') || orgDestDir.endsWith(Option::dir_sep)))
+ destDir += Option::dir_sep;
+ QString target = QString(project->first("TARGET")+project->first("TARGET_EXT"));
+ target.remove("\"");
+ project->values("DEST_TARGET").prepend(destDir + target);
+
+ writeObjectsPart(t);
+
+ writeExtraCompilerVariables(t);
+ writeExtraVariables(t);
+
+ t << "DIST = " << varList("DISTFILES") << endl;
+ t << "QMAKE_TARGET = " << var("QMAKE_ORIG_TARGET") << endl;
+ // The comment is important to maintain variable compatibility with Unix
+ // Makefiles, while not interpreting a trailing-slash as a linebreak
+ t << "DESTDIR = " << escapeFilePath(destDir) << " #avoid trailing-slash linebreak" << endl;
+ t << "TARGET = " << escapeFilePath(target) << endl;
+ t << "DESTDIR_TARGET = " << escapeFilePath(var("DEST_TARGET")) << endl;
+ t << endl;
+
+ t << "####### Implicit rules" << endl << endl;
+ writeImplicitRulesPart(t);
+
+ t << "####### Build rules" << endl << endl;
+ writeBuildRulesPart(t);
+
+ if(project->isActiveConfig("shared") && !project->values("DLLDESTDIR").isEmpty()) {
+ QStringList dlldirs = project->values("DLLDESTDIR");
+ for (QStringList::Iterator dlldir = dlldirs.begin(); dlldir != dlldirs.end(); ++dlldir) {
+ t << "\t" << "-$(COPY_FILE) \"$(DESTDIR_TARGET)\" " << Option::fixPathToTargetOS(*dlldir, false) << endl;
+ }
+ }
+ t << endl;
+
+ writeRcFilePart(t);
+
+ writeMakeQmake(t);
+
+ QStringList dist_files = fileFixify(Option::mkfile::project_files);
+ if(!project->isEmpty("QMAKE_INTERNAL_INCLUDED_FILES"))
+ dist_files += project->values("QMAKE_INTERNAL_INCLUDED_FILES");
+ if(!project->isEmpty("TRANSLATIONS"))
+ dist_files << var("TRANSLATIONS");
+ if(!project->isEmpty("FORMS")) {
+ QStringList &forms = project->values("FORMS");
+ for(QStringList::Iterator formit = forms.begin(); formit != forms.end(); ++formit) {
+ QString ui_h = fileFixify((*formit) + Option::h_ext.first());
+ if(exists(ui_h))
+ dist_files << ui_h;
+ }
+ }
+ t << "dist:" << "\n\t"
+ << "$(ZIP) " << var("QMAKE_ORIG_TARGET") << ".zip " << "$(SOURCES) $(DIST) "
+ << dist_files.join(" ") << " " << var("TRANSLATIONS") << " ";
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const QStringList &inputs = project->values((*it)+".input");
+ for(QStringList::ConstIterator input = inputs.begin(); input != inputs.end(); ++input) {
+ t << (*input) << " ";
+ }
+ }
+ }
+ t << endl << endl;
+
+ writeCleanParts(t);
+ writeExtraTargets(t);
+ writeExtraCompilerTargets(t);
+ t << endl << endl;
+}
+
+void Win32MakefileGenerator::writeLibsPart(QTextStream &t)
+{
+ if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
+ t << "LIBAPP = " << var("QMAKE_LIB") << endl;
+ t << "LIBFLAGS = " << var("QMAKE_LIBFLAGS") << endl;
+ } else {
+ t << "LINK = " << var("QMAKE_LINK") << endl;
+ t << "LFLAGS = ";
+ if(!project->values("QMAKE_LIBDIR").isEmpty())
+ writeLibDirPart(t);
+ t << var("QMAKE_LFLAGS") << endl;
+ t << "LIBS = " << var("QMAKE_LIBS") << " " << var("QMAKE_LIBS_PRIVATE") << endl;
+ }
+}
+
+void Win32MakefileGenerator::writeLibDirPart(QTextStream &t)
+{
+ QStringList libDirs = project->values("QMAKE_LIBDIR");
+ for (int i = 0; i < libDirs.size(); ++i)
+ libDirs[i].remove("\"");
+ t << valGlue(libDirs,"-L\"","\" -L\"","\"") << " ";
+}
+
+void Win32MakefileGenerator::writeObjectsPart(QTextStream &t)
+{
+ t << "OBJECTS = " << valList(escapeDependencyPaths(project->values("OBJECTS"))) << endl;
+}
+
+void Win32MakefileGenerator::writeImplicitRulesPart(QTextStream &t)
+{
+ t << ".SUFFIXES:";
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << " " << (*cppit);
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << " " << (*cit);
+ t << endl << endl;
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << (*cppit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CXX_IMP") << endl << endl;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << (*cit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CC_IMP") << endl << endl;
+}
+
+void Win32MakefileGenerator::writeBuildRulesPart(QTextStream &)
+{
+}
+
+void Win32MakefileGenerator::writeRcFilePart(QTextStream &t)
+{
+ if(!project->values("RC_FILE").isEmpty()) {
+ const QString res_file = project->first("RES_FILE"),
+ rc_file = fileFixify(project->first("RC_FILE"));
+ // The resource tool needs to have the same defines passed in as the compiler, since you may
+ // use these defines in the .rc file itself. Also, we need to add the _DEBUG define manually
+ // since the compiler defines this symbol by itself, and we use it in the automatically
+ // created rc file when VERSION is define the .pro file.
+ t << res_file << ": " << rc_file << "\n\t"
+ << var("QMAKE_RC") << (project->isActiveConfig("debug") ? " -D_DEBUG" : "") << " $(DEFINES) -fo " << res_file << " " << rc_file;
+ t << endl << endl;
+ }
+}
+
+QString Win32MakefileGenerator::getLibTarget()
+{
+ return QString(project->first("TARGET") + project->first("TARGET_VERSION_EXT") + ".lib");
+}
+
+QString Win32MakefileGenerator::defaultInstall(const QString &t)
+{
+ if((t != "target" && t != "dlltarget") ||
+ (t == "dlltarget" && (project->first("TEMPLATE") != "lib" || !project->isActiveConfig("shared"))) ||
+ project->first("TEMPLATE") == "subdirs")
+ return QString();
+
+ const QString root = "$(INSTALL_ROOT)";
+ QStringList &uninst = project->values(t + ".uninstall");
+ QString ret;
+ QString targetdir = Option::fixPathToTargetOS(project->first(t + ".path"), false);
+ targetdir = fileFixify(targetdir, FileFixifyAbsolute);
+ if(targetdir.right(1) != Option::dir_sep)
+ targetdir += Option::dir_sep;
+
+ if(t == "target" && project->first("TEMPLATE") == "lib") {
+ if(project->isActiveConfig("create_prl") && !project->isActiveConfig("no_install_prl") &&
+ !project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) {
+ QString dst_prl = Option::fixPathToTargetOS(project->first("QMAKE_INTERNAL_PRL_FILE"));
+ int slsh = dst_prl.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ dst_prl = dst_prl.right(dst_prl.length() - slsh - 1);
+ dst_prl = filePrefixRoot(root, targetdir + dst_prl);
+ ret += "-$(INSTALL_FILE) \"" + project->first("QMAKE_INTERNAL_PRL_FILE") + "\" \"" + dst_prl + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_prl + "\"");
+ }
+ if(project->isActiveConfig("create_pc")) {
+ QString dst_pc = pkgConfigFileName(false);
+ if (!dst_pc.isEmpty()) {
+ dst_pc = filePrefixRoot(root, targetdir + dst_pc);
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += "-$(INSTALL_FILE) \"" + pkgConfigFileName(true) + "\" \"" + dst_pc + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_pc + "\"");
+ }
+ }
+ if(project->isActiveConfig("shared") && !project->isActiveConfig("plugin")) {
+ QString lib_target = getLibTarget();
+ lib_target.remove('"');
+ QString src_targ = (project->isEmpty("DESTDIR") ? QString("$(DESTDIR)") : project->first("DESTDIR")) + lib_target;
+ QString dst_targ = filePrefixRoot(root, fileFixify(targetdir + lib_target, FileFixifyAbsolute));
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += QString("-$(INSTALL_FILE)") + " \"" + src_targ + "\" \"" + dst_targ + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_targ + "\"");
+ }
+ }
+
+ if(t == "dlltarget" || project->values(t + ".CONFIG").indexOf("no_dll") == -1) {
+ QString src_targ = "$(DESTDIR_TARGET)";
+ QString dst_targ = filePrefixRoot(root, fileFixify(targetdir + "$(TARGET)", FileFixifyAbsolute));
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += QString("-$(INSTALL_FILE)") + " \"" + src_targ + "\" \"" + dst_targ + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_targ + "\"");
+ }
+ return ret;
+}
+
+QString Win32MakefileGenerator::escapeFilePath(const QString &path) const
+{
+ QString ret = path;
+ if(!ret.isEmpty()) {
+ ret = unescapeFilePath(ret);
+ if(ret.contains(" "))
+ ret = "\"" + ret + "\"";
+ debug_msg(2, "EscapeFilePath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
+ }
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/winmakefile.h b/qmake/generators/win32/winmakefile.h
new file mode 100644
index 0000000000..fb11e1ae9d
--- /dev/null
+++ b/qmake/generators/win32/winmakefile.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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 WINMAKEFILE_H
+#define WINMAKEFILE_H
+
+#include "makefile.h"
+
+QT_BEGIN_NAMESPACE
+
+// In the Qt evaluation and educational version, we have a postfix in the
+// library name (e.g. qtmteval301.dll). QTDLL_POSTFIX is used for this.
+// A script modifies these lines when building eval/edu version, so be careful
+// when changing them.
+#ifndef QTDLL_POSTFIX
+#define QTDLL_POSTFIX ""
+#endif
+
+class Win32MakefileGenerator : public MakefileGenerator
+{
+public:
+ Win32MakefileGenerator();
+ ~Win32MakefileGenerator();
+protected:
+ virtual QString defaultInstall(const QString &);
+ virtual void writeCleanParts(QTextStream &t);
+ virtual void writeStandardParts(QTextStream &t);
+ virtual void writeIncPart(QTextStream &t);
+ virtual void writeLibDirPart(QTextStream &t);
+ virtual void writeLibsPart(QTextStream &t);
+ virtual void writeObjectsPart(QTextStream &t);
+ virtual void writeImplicitRulesPart(QTextStream &t);
+ virtual void writeBuildRulesPart(QTextStream &);
+ virtual QString escapeFilePath(const QString &path) const;
+
+ virtual void writeRcFilePart(QTextStream &t);
+
+ int findHighestVersion(const QString &dir, const QString &stem, const QString &ext = QLatin1String("lib"));
+ bool findLibraries(const QString &);
+ virtual bool findLibraries();
+
+ virtual void processPrlFiles();
+ virtual void processVars();
+ virtual void fixTargetExt();
+ virtual void processRcFileVar();
+ virtual void processFileTagsVar();
+ virtual QString getLibTarget();
+};
+
+inline Win32MakefileGenerator::~Win32MakefileGenerator()
+{ }
+
+inline bool Win32MakefileGenerator::findLibraries()
+{ return findLibraries("QMAKE_LIBS") && findLibraries("QMAKE_LIBS_PRIVATE"); }
+
+QT_END_NAMESPACE
+
+#endif // WINMAKEFILE_H
diff --git a/qmake/generators/xmloutput.cpp b/qmake/generators/xmloutput.cpp
new file mode 100644
index 0000000000..8b049ad04a
--- /dev/null
+++ b/qmake/generators/xmloutput.cpp
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** 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 "xmloutput.h"
+
+QT_BEGIN_NAMESPACE
+
+XmlOutput::XmlOutput(QTextStream &file, ConverstionType type)
+ : xmlFile(file), indent("\t"), currentLevel(0), currentState(Bare), format(NewLine),
+ conversion(type)
+{
+ tagStack.clear();
+}
+
+XmlOutput::~XmlOutput()
+{
+ closeAll();
+}
+
+// Settings ------------------------------------------------------------------
+void XmlOutput::setIndentString(const QString &indentString)
+{
+ indent = indentString;
+}
+
+QString XmlOutput::indentString()
+{
+ return indent;
+}
+
+void XmlOutput::setIndentLevel(int level)
+{
+ currentLevel = level;
+}
+
+int XmlOutput::indentLevel()
+{
+ return currentLevel;
+}
+
+void XmlOutput::setState(XMLState state)
+{
+ currentState = state;
+}
+
+void XmlOutput::setFormat(XMLFormat newFormat)
+{
+ format = newFormat;
+}
+
+XmlOutput::XMLState XmlOutput::state()
+{
+ return currentState;
+}
+
+void XmlOutput::updateIndent()
+{
+ currentIndent.clear();
+ for (int i = 0; i < currentLevel; ++i)
+ currentIndent.append(indent);
+}
+
+void XmlOutput::increaseIndent()
+{
+ ++currentLevel;
+ updateIndent();
+}
+
+void XmlOutput::decreaseIndent()
+{
+ if (currentLevel)
+ --currentLevel;
+ updateIndent();
+ if (!currentLevel)
+ currentState = Bare;
+}
+
+QString XmlOutput::doConversion(const QString &text)
+{
+ if (!text.count())
+ return QString();
+ else if (conversion == NoConversion)
+ return text;
+
+ QString output;
+ if (conversion == XMLConversion) {
+
+ // this is a way to escape characters that shouldn't be converted
+ for (int i=0; i<text.count(); ++i) {
+ if (text.at(i) == QLatin1Char('&')) {
+ if ( (i + 7) < text.count() &&
+ text.at(i + 1) == QLatin1Char('#') &&
+ text.at(i + 2) == QLatin1Char('x') &&
+ text.at(i + 7) == QLatin1Char(';') ) {
+ output += text.at(i);
+ } else {
+ output += QLatin1String("&amp;");
+ }
+ } else {
+ QChar c = text.at(i);
+ if (c.unicode() < 0x20) {
+ output += QString("&#x%1;").arg(c.unicode(), 2, 16, QLatin1Char('0'));
+ } else {
+ output += text.at(i);
+ }
+ }
+ }
+ } else {
+ output = text;
+ }
+
+ if (conversion == XMLConversion) {
+ output.replace('\"', "&quot;");
+ output.replace('\'', "&apos;");
+ } else if (conversion == EscapeConversion) {
+ output.replace('\"', "\\\"");
+ output.replace('\'', "\\\'");
+ }
+ return output;
+}
+
+// Stream functions ----------------------------------------------------------
+XmlOutput& XmlOutput::operator<<(const QString& o)
+{
+ return operator<<(data(o));
+}
+
+XmlOutput& XmlOutput::operator<<(const xml_output& o)
+{
+ switch(o.xo_type) {
+ case tNothing:
+ break;
+ case tRaw:
+ addRaw(o.xo_text);
+ break;
+ case tDeclaration:
+ addDeclaration(o.xo_text, o.xo_value);
+ break;
+ case tTag:
+ newTagOpen(o.xo_text);
+ break;
+ case tTagValue:
+ addRaw(QString("\n%1<%2>").arg(currentIndent).arg(o.xo_text));
+ addRaw(QString("%1").arg(o.xo_value));
+ addRaw(QString("</%1>").arg(o.xo_text));
+ break;
+ case tValueTag:
+ addRaw(QString("%1").arg(doConversion(o.xo_text)));
+ setFormat(NoNewLine);
+ closeTag();
+ setFormat(NewLine);
+ break;
+ case tImport:
+ addRaw(QString("\n%1<Import %2=\"%3\" />").arg(currentIndent).arg(o.xo_text).arg(o.xo_value));
+ break;
+ case tCloseTag:
+ if (o.xo_value.count())
+ closeAll();
+ else if (o.xo_text.count())
+ closeTo(o.xo_text);
+ else
+ closeTag();
+ break;
+ case tAttribute:
+ addAttribute(o.xo_text, o.xo_value);
+ break;
+ case tAttributeTag:
+ addAttributeTag(o.xo_text, o.xo_value);
+ break;
+ case tData:
+ {
+ // Special case to be able to close tag in normal
+ // way ("</tag>", not "/>") without using addRaw()..
+ if (!o.xo_text.count()) {
+ closeOpen();
+ break;
+ }
+ QString output = doConversion(o.xo_text);
+ output.replace('\n', "\n" + currentIndent);
+ addRaw(QString("\n%1%2").arg(currentIndent).arg(output));
+ }
+ break;
+ case tComment:
+ {
+ QString output("<!--%1-->");
+ addRaw(output.arg(o.xo_text));
+ }
+ break;
+ case tCDATA:
+ {
+ QString output("<![CDATA[\n%1\n]]>");
+ addRaw(output.arg(o.xo_text));
+ }
+ break;
+ }
+ return *this;
+}
+
+
+// Output functions ----------------------------------------------------------
+void XmlOutput::newTag(const QString &tag)
+{
+ Q_ASSERT_X(tag.count(), "XmlOutput", "Cannot open an empty tag");
+ newTagOpen(tag);
+ closeOpen();
+}
+
+void XmlOutput::newTagOpen(const QString &tag)
+{
+ Q_ASSERT_X(tag.count(), "XmlOutput", "Cannot open an empty tag");
+ closeOpen();
+
+ if (format == NewLine)
+ xmlFile << endl << currentIndent;
+ xmlFile << '<' << doConversion(tag);
+ currentState = Attribute;
+ tagStack.append(tag);
+ increaseIndent(); // ---> indent
+}
+
+void XmlOutput::closeOpen()
+{
+ switch(currentState) {
+ case Bare:
+ case Tag:
+ return;
+ case Attribute:
+ break;
+ }
+ xmlFile << '>';
+ currentState = Tag;
+}
+
+void XmlOutput::closeTag()
+{
+ switch(currentState) {
+ case Bare:
+ if (tagStack.count())
+ //warn_msg(WarnLogic, "<Root>: Cannot close tag in Bare state, %d tags on stack", tagStack.count());
+ qDebug("<Root>: Cannot close tag in Bare state, %d tags on stack", tagStack.count());
+ else
+ //warn_msg(WarnLogic, "<Root>: Cannot close tag, no tags on stack");
+ qDebug("<Root>: Cannot close tag, no tags on stack");
+ return;
+ case Tag:
+ decreaseIndent(); // <--- Pre-decrease indent
+ if (format == NewLine)
+ xmlFile << endl << currentIndent;
+ xmlFile << "</" << doConversion(tagStack.last()) << '>';
+ tagStack.pop_back();
+ break;
+ case Attribute:
+ xmlFile << " />";
+ tagStack.pop_back();
+ currentState = Tag;
+ decreaseIndent(); // <--- Post-decrease indent
+ break;
+ }
+}
+
+void XmlOutput::closeTo(const QString &tag)
+{
+ bool cont = true;
+ if (!tagStack.contains(tag) && !tag.isNull()) {
+ //warn_msg(WarnLogic, "<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().latin1(), tag.latin1());
+ qDebug("<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().toLatin1().constData(), tag.toLatin1().constData());
+ return;
+ }
+ int left = tagStack.count();
+ while (left-- && cont) {
+ cont = tagStack.last().compare(tag) != 0;
+ closeTag();
+ }
+}
+
+void XmlOutput::closeAll()
+{
+ if (!tagStack.count())
+ return;
+ closeTo(QString());
+}
+
+void XmlOutput::addDeclaration(const QString &version, const QString &encoding)
+{
+ switch(currentState) {
+ case Bare:
+ break;
+ case Tag:
+ case Attribute:
+ //warn_msg(WarnLogic, "<%s>: Cannot add declaration when not in bare state", tagStack.last().toLatin1().constData());
+ qDebug("<%s>: Cannot add declaration when not in bare state", tagStack.last().toLatin1().constData());
+ return;
+ }
+ QString outData = QString("<?xml version=\"%1\" encoding=\"%2\"?>")
+ .arg(doConversion(version))
+ .arg(doConversion(encoding));
+ addRaw(outData);
+}
+
+void XmlOutput::addRaw(const QString &rawText)
+{
+ closeOpen();
+ xmlFile << rawText;
+}
+
+void XmlOutput::addAttribute(const QString &attribute, const QString &value)
+{
+ switch(currentState) {
+ case Bare:
+ case Tag:
+ //warn_msg(WarnLogic, "<%s>: Cannot add attribute since tags not open", tagStack.last().toLatin1().constData());
+ qDebug("<%s>: Cannot add attribute (%s) since tag's not open",
+ (tagStack.count() ? tagStack.last().toLatin1().constData() : "Root"),
+ attribute.toLatin1().constData());
+ return;
+ case Attribute:
+ break;
+ }
+ if (format == NewLine)
+ xmlFile << endl;
+ xmlFile << currentIndent << doConversion(attribute) << "=\"" << doConversion(value) << "\"";
+}
+
+void XmlOutput::addAttributeTag(const QString &attribute, const QString &value)
+{
+ switch(currentState) {
+ case Bare:
+ case Tag:
+ //warn_msg(WarnLogic, "<%s>: Cannot add attribute since tags not open", tagStack.last().toLatin1().constData());
+ qDebug("<%s>: Cannot add attribute (%s) since tag's not open",
+ (tagStack.count() ? tagStack.last().toLatin1().constData() : "Root"),
+ attribute.toLatin1().constData());
+ return;
+ case Attribute:
+ break;
+ }
+ xmlFile << " " << doConversion(attribute) << "=\"" << doConversion(value) << "\"";
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/xmloutput.h b/qmake/generators/xmloutput.h
new file mode 100644
index 0000000000..9b97a3da94
--- /dev/null
+++ b/qmake/generators/xmloutput.h
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** 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 XMLOUTPUT_H
+#define XMLOUTPUT_H
+
+#include <qtextstream.h>
+#include <qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+class XmlOutput
+{
+public:
+ enum ConverstionType {
+ NoConversion, // No change
+ EscapeConversion, // Use '\"'
+ XMLConversion // Use &quot;
+ };
+ enum XMLFormat {
+ NoNewLine, // No new lines, unless added manually
+ NewLine // All properties & tags indented on new lines
+ };
+ enum XMLState {
+ Bare, // Not in tag or attribute
+ Tag, // <tagname attribute1="value"
+ Attribute // attribute2="value">
+ };
+ enum XMLType {
+ tNothing, // No XML output, and not state change
+ tRaw, // Raw text (no formating)
+ tDeclaration, // <?xml version="x.x" encoding="xxx"?>
+ tTag, // <tagname attribute1="value"
+ tTagValue, // <tagname>value</tagname>
+ tValueTag, // value</tagname>
+ tCloseTag, // Closes an open tag
+ tAttribute, // attribute2="value">
+ tAttributeTag, // attribute on the same line as a tag
+ tData, // Tag data (formating done)
+ tImport, // <import "type"="path" />
+ tComment, // <!-- Comment -->
+ tCDATA // <![CDATA[ ... ]]>
+ };
+
+ XmlOutput(QTextStream &file, ConverstionType type = XMLConversion);
+ ~XmlOutput();
+
+ // Settings
+ void setIndentString(const QString &indentString);
+ QString indentString();
+ void setIndentLevel(int level);
+ int indentLevel();
+ void setState(XMLState state);
+ void setFormat(XMLFormat newFormat);
+ XMLState state();
+
+
+ struct xml_output {
+ XMLType xo_type; // Type of struct instance
+ QString xo_text; // Tag/Attribute name/xml version
+ QString xo_value; // Value of attributes/xml encoding
+
+ xml_output(XMLType type, const QString &text, const QString &value)
+ : xo_type(type), xo_text(text), xo_value(value) {}
+ xml_output(const xml_output &xo)
+ : xo_type(xo.xo_type), xo_text(xo.xo_text), xo_value(xo.xo_value) {}
+ };
+
+ // Streams
+ XmlOutput& operator<<(const QString& o);
+ XmlOutput& operator<<(const xml_output& o);
+
+private:
+ void increaseIndent();
+ void decreaseIndent();
+ void updateIndent();
+
+ QString doConversion(const QString &text);
+
+ // Output functions
+ void newTag(const QString &tag);
+ void newTagOpen(const QString &tag);
+ void closeOpen();
+ void closeTag();
+ void closeTo(const QString &tag);
+ void closeAll();
+
+ void addDeclaration(const QString &version, const QString &encoding);
+ void addRaw(const QString &rawText);
+ void addAttribute(const QString &attribute, const QString &value);
+ void addAttributeTag(const QString &attribute, const QString &value);
+ void addData(const QString &data);
+
+ // Data
+ QTextStream &xmlFile;
+ QString indent;
+
+ QString currentIndent;
+ int currentLevel;
+ XMLState currentState;
+
+ XMLFormat format;
+ ConverstionType conversion;
+ QStack<QString> tagStack;
+};
+
+inline XmlOutput::xml_output noxml()
+{
+ return XmlOutput::xml_output(XmlOutput::tNothing, QString(), QString());
+}
+
+inline XmlOutput::xml_output raw(const QString &rawText)
+{
+ return XmlOutput::xml_output(XmlOutput::tRaw, rawText, QString());
+}
+
+inline XmlOutput::xml_output declaration(const QString &version = QString("1.0"),
+ const QString &encoding = QString())
+{
+ return XmlOutput::xml_output(XmlOutput::tDeclaration, version, encoding);
+}
+
+inline XmlOutput::xml_output decl(const QString &version = QString("1.0"),
+ const QString &encoding = QString())
+{
+ return declaration(version, encoding);
+}
+
+inline XmlOutput::xml_output tag(const QString &name)
+{
+ return XmlOutput::xml_output(XmlOutput::tTag, name, QString());
+}
+
+
+inline XmlOutput::xml_output valueTag(const QString &value)
+{
+ return XmlOutput::xml_output(XmlOutput::tValueTag, value, QString());
+}
+
+inline XmlOutput::xml_output tagValue(const QString &tagName, const QString &value)
+{
+ return XmlOutput::xml_output(XmlOutput::tTagValue, tagName, value);
+}
+
+inline XmlOutput::xml_output import(const QString &tagName, const QString &value)
+{
+ return XmlOutput::xml_output(XmlOutput::tImport, tagName, value);
+}
+
+inline XmlOutput::xml_output closetag()
+{
+ return XmlOutput::xml_output(XmlOutput::tCloseTag, QString(), QString());
+}
+
+inline XmlOutput::xml_output closetag(const QString &toTag)
+{
+ return XmlOutput::xml_output(XmlOutput::tCloseTag, toTag, QString());
+}
+
+inline XmlOutput::xml_output closeall()
+{
+ return XmlOutput::xml_output(XmlOutput::tCloseTag, QString(), QString("all"));
+}
+
+inline XmlOutput::xml_output attribute(const QString &name,
+ const QString &value)
+{
+ return XmlOutput::xml_output(XmlOutput::tAttribute, name, value);
+}
+
+inline XmlOutput::xml_output attributeTag(const QString &name,
+ const QString &value)
+{
+ return XmlOutput::xml_output(XmlOutput::tAttributeTag, name, value);
+}
+
+inline XmlOutput::xml_output attr(const QString &name,
+ const QString &value)
+{
+ return attribute(name, value);
+}
+
+inline XmlOutput::xml_output attrTag(const QString &name,
+ const QString &value)
+{
+ return attributeTag(name, value);
+}
+
+inline XmlOutput::xml_output data(const QString &text = QString())
+{
+ return XmlOutput::xml_output(XmlOutput::tData, text, QString());
+}
+
+inline XmlOutput::xml_output comment(const QString &text)
+{
+ return XmlOutput::xml_output(XmlOutput::tComment, text, QString());
+}
+
+inline XmlOutput::xml_output cdata(const QString &text)
+{
+ return XmlOutput::xml_output(XmlOutput::tCDATA, text, QString());
+}
+
+QT_END_NAMESPACE
+
+#endif // XMLOUTPUT_H
diff --git a/qmake/main.cpp b/qmake/main.cpp
new file mode 100644
index 0000000000..7d4d458b0d
--- /dev/null
+++ b/qmake/main.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** 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 "project.h"
+#include "property.h"
+#include "option.h"
+#include "cachekeys.h"
+#include "metamakefile.h"
+#include <qnamespace.h>
+#include <qdebug.h>
+#include <qregexp.h>
+#include <qdir.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+QT_BEGIN_NAMESPACE
+
+// for Borland, main is defined to qMain which breaks qmake
+#undef main
+#ifdef Q_OS_MAC
+#endif
+
+/* This is to work around lame implementation on Darwin. It has been noted that the getpwd(3) function
+ is much too slow, and called much too often inside of Qt (every fileFixify). With this we use a locally
+ cached copy because I can control all the times it is set (because Qt never sets the pwd under me).
+*/
+static QString pwd;
+QString qmake_getpwd()
+{
+ if(pwd.isNull())
+ pwd = QDir::currentPath();
+ return pwd;
+}
+bool qmake_setpwd(const QString &p)
+{
+ if(QDir::setCurrent(p)) {
+ pwd = QDir::currentPath();
+ return true;
+ }
+ return false;
+}
+
+int runQMake(int argc, char **argv)
+{
+ // stderr is unbuffered by default, but stdout buffering depends on whether
+ // there is a terminal attached. Buffering can make output from stderr and stdout
+ // appear out of sync, so force stdout to be unbuffered as well.
+ // This is particularly important for things like QtCreator and scripted builds.
+ setvbuf(stdout, (char *)NULL, _IONBF, 0);
+
+ // parse command line
+ int ret = Option::init(argc, argv);
+ if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
+ if ((ret & Option::QMAKE_CMDLINE_ERROR) != 0)
+ return 1;
+ return 0;
+ }
+
+ QString oldpwd = qmake_getpwd();
+#ifdef Q_WS_WIN
+ if(!(oldpwd.length() == 3 && oldpwd[0].isLetter() && oldpwd.endsWith(":/")))
+#endif
+ {
+ if(oldpwd.right(1) != QString(QChar(QDir::separator())))
+ oldpwd += QDir::separator();
+ }
+ Option::output_dir = oldpwd; //for now this is the output dir
+
+ if(Option::output.fileName() != "-") {
+ QFileInfo fi(Option::output);
+ QString dir;
+ if(fi.isDir()) {
+ dir = fi.filePath();
+ } else {
+ QString tmp_dir = fi.path();
+ if(!tmp_dir.isEmpty() && QFile::exists(tmp_dir))
+ dir = tmp_dir;
+ }
+ if(!dir.isNull() && dir != ".")
+ Option::output_dir = dir;
+ if(QDir::isRelativePath(Option::output_dir))
+ Option::output_dir.prepend(oldpwd);
+ Option::output_dir = QDir::cleanPath(Option::output_dir);
+ }
+
+ QMakeProperty prop;
+ if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY ||
+ Option::qmake_mode == Option::QMAKE_SET_PROPERTY ||
+ Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY)
+ return prop.exec() ? 0 : 101;
+
+ QMakeProject project(&prop);
+ int exit_val = 0;
+ QStringList files;
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
+ files << "(*hack*)"; //we don't even use files, but we do the for() body once
+ else
+ files = Option::mkfile::project_files;
+ for(QStringList::Iterator pfile = files.begin(); pfile != files.end(); pfile++) {
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+ Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
+ QString fn = Option::fixPathToLocalOS((*pfile));
+ if(!QFile::exists(fn)) {
+ fprintf(stderr, "Cannot find file: %s.\n", fn.toLatin1().constData());
+ exit_val = 2;
+ continue;
+ }
+
+ //setup pwd properly
+ debug_msg(1, "Resetting dir to: %s", oldpwd.toLatin1().constData());
+ qmake_setpwd(oldpwd); //reset the old pwd
+ int di = fn.lastIndexOf(QDir::separator());
+ if(di != -1) {
+ debug_msg(1, "Changing dir to: %s", fn.left(di).toLatin1().constData());
+ if(!qmake_setpwd(fn.left(di)))
+ fprintf(stderr, "Cannot find directory: %s\n", fn.left(di).toLatin1().constData());
+ fn = fn.right(fn.length() - di - 1);
+ }
+
+ // read project..
+ if(!project.read(fn)) {
+ fprintf(stderr, "Error processing project file: %s\n",
+ fn == "-" ? "(stdin)" : (*pfile).toLatin1().constData());
+ exit_val = 3;
+ continue;
+ }
+ if(Option::mkfile::do_preprocess) //no need to create makefile
+ continue;
+ }
+
+ bool success = true;
+ MetaMakefileGenerator *mkfile = MetaMakefileGenerator::createMetaGenerator(&project, QString(), false, &success);
+ if (!success)
+ exit_val = 3;
+
+ if(mkfile && !mkfile->write(oldpwd)) {
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
+ fprintf(stderr, "Unable to generate project file.\n");
+ else
+ fprintf(stderr, "Unable to generate makefile for: %s\n", (*pfile).toLatin1().constData());
+ exit_val = 5;
+ }
+ delete mkfile;
+ mkfile = NULL;
+ }
+ qmakeClearCaches();
+ return exit_val;
+}
+
+QT_END_NAMESPACE
+
+int main(int argc, char **argv)
+{
+ return QT_PREPEND_NAMESPACE(runQMake)(argc, argv);
+}
diff --git a/qmake/meta.cpp b/qmake/meta.cpp
new file mode 100644
index 0000000000..ef822a6940
--- /dev/null
+++ b/qmake/meta.cpp
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** 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 "meta.h"
+#include "project.h"
+#include "option.h"
+#include <qdir.h>
+
+QT_BEGIN_NAMESPACE
+
+QMap<QString, QMap<QString, QStringList> > QMakeMetaInfo::cache_vars;
+
+QMakeMetaInfo::QMakeMetaInfo()
+{
+
+}
+
+
+bool
+QMakeMetaInfo::readLib(QString lib)
+{
+ clear();
+ QString meta_file = findLib(lib);
+
+ if(cache_vars.contains(meta_file)) {
+ vars = cache_vars[meta_file];
+ return true;
+ }
+
+ bool ret = false;
+ if(!meta_file.isNull()) {
+ if(meta_file.endsWith(Option::pkgcfg_ext)) {
+ if((ret=readPkgCfgFile(meta_file)))
+ meta_type = "pkgcfg";
+ } else if(meta_file.endsWith(Option::libtool_ext)) {
+ if((ret=readLibtoolFile(meta_file)))
+ meta_type = "libtool";
+ } else if(meta_file.endsWith(Option::prl_ext)) {
+ QMakeProject proj;
+ if(!proj.read(Option::fixPathToLocalOS(meta_file), QMakeProject::ReadProFile))
+ return false;
+ meta_type = "qmake";
+ vars = proj.variables();
+ ret = true;
+ } else {
+ warn_msg(WarnLogic, "QMakeMetaInfo: unknown file format for %s", meta_file.toLatin1().constData());
+ }
+ }
+ if(ret)
+ cache_vars.insert(meta_file, vars);
+ return ret;
+}
+
+
+void
+QMakeMetaInfo::clear()
+{
+ vars.clear();
+}
+
+
+QString
+QMakeMetaInfo::findLib(QString lib)
+{
+ if((lib[0] == '\'' || lib[0] == '"') &&
+ lib[lib.length()-1] == lib[0])
+ lib = lib.mid(1, lib.length()-2);
+ lib = Option::fixPathToLocalOS(lib);
+
+ QString ret;
+ QString extns[] = { Option::prl_ext, /*Option::pkgcfg_ext, Option::libtool_ext,*/ QString() };
+ for(int extn = 0; !extns[extn].isNull(); extn++) {
+ if(lib.endsWith(extns[extn]))
+ ret = QFile::exists(lib) ? lib : QString();
+ }
+ if(ret.isNull()) {
+ for(int extn = 0; !extns[extn].isNull(); extn++) {
+ if(QFile::exists(lib + extns[extn])) {
+ ret = lib + extns[extn];
+ break;
+ }
+ }
+ }
+ if(ret.isNull()) {
+ debug_msg(2, "QMakeMetaInfo: Cannot find info file for %s", lib.toLatin1().constData());
+ } else {
+ debug_msg(2, "QMakeMetaInfo: Found info file %s for %s", ret.toLatin1().constData(), lib.toLatin1().constData());
+ }
+ return ret;
+}
+
+
+bool
+QMakeMetaInfo::readLibtoolFile(const QString &f)
+{
+ /* I can just run the .la through the .pro parser since they are compatible.. */
+ QMakeProject proj;
+ if(!proj.read(Option::fixPathToLocalOS(f), QMakeProject::ReadProFile))
+ return false;
+ QString dirf = Option::fixPathToTargetOS(f).section(Option::dir_sep, 0, -2);
+ if(dirf == f)
+ dirf = "";
+ else if(!dirf.isEmpty() && !dirf.endsWith(Option::output_dir))
+ dirf += Option::dir_sep;
+ QMap<QString, QStringList> &v = proj.variables();
+ for(QMap<QString, QStringList>::Iterator it = v.begin(); it != v.end(); ++it) {
+ QStringList lst = it.value();
+ if(lst.count() == 1 && (lst.first().startsWith("'") || lst.first().startsWith("\"")) &&
+ lst.first().endsWith(QString(lst.first()[0])))
+ lst = QStringList(lst.first().mid(1, lst.first().length() - 2));
+ if(!vars.contains("QMAKE_PRL_TARGET") &&
+ (it.key() == "dlname" || it.key() == "library_names" || it.key() == "old_library")) {
+ QString dir = v["libdir"].first();
+ if((dir.startsWith("'") || dir.startsWith("\"")) && dir.endsWith(QString(dir[0])))
+ dir = dir.mid(1, dir.length() - 2);
+ dir = dir.trimmed();
+ if(!dir.isEmpty() && !dir.endsWith(Option::dir_sep))
+ dir += Option::dir_sep;
+ if(lst.count() == 1)
+ lst = lst.first().split(" ");
+ for(QStringList::Iterator lst_it = lst.begin(); lst_it != lst.end(); ++lst_it) {
+ bool found = false;
+ QString dirs[] = { "", dir, dirf, dirf + ".libs" + QDir::separator(), "(term)" };
+ for(int i = 0; !found && dirs[i] != "(term)"; i++) {
+ if(QFile::exists(dirs[i] + (*lst_it))) {
+ QString targ = dirs[i] + (*lst_it);
+ if(QDir::isRelativePath(targ))
+ targ.prepend(qmake_getpwd() + QDir::separator());
+ vars["QMAKE_PRL_TARGET"] << targ;
+ found = true;
+ }
+ }
+ if(found)
+ break;
+ }
+ } else if(it.key() == "dependency_libs") {
+ if(lst.count() == 1) {
+ QString dep = lst.first();
+ if((dep.startsWith("'") || dep.startsWith("\"")) && dep.endsWith(QString(dep[0])))
+ dep = dep.mid(1, dep.length() - 2);
+ lst = dep.trimmed().split(" ");
+ }
+ QMakeProject *conf = NULL;
+ for(QStringList::Iterator lit = lst.begin(); lit != lst.end(); ++lit) {
+ if((*lit).startsWith("-R")) {
+ if(!conf) {
+ conf = new QMakeProject;
+ conf->read(QMakeProject::ReadAll ^ QMakeProject::ReadProFile);
+ }
+ if(!conf->isEmpty("QMAKE_LFLAGS_RPATH"))
+ (*lit) = conf->first("QMAKE_LFLAGS_RPATH") + (*lit).mid(2);
+ }
+ }
+ if(conf)
+ delete conf;
+ vars["QMAKE_PRL_LIBS"] += lst;
+ }
+ }
+ return true;
+}
+
+bool
+QMakeMetaInfo::readPkgCfgFile(const QString &f)
+{
+ fprintf(stderr, "Must implement reading in pkg-config files (%s)!!!\n", f.toLatin1().constData());
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/meta.h b/qmake/meta.h
new file mode 100644
index 0000000000..5fd3e7220d
--- /dev/null
+++ b/qmake/meta.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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 META_H
+#define META_H
+
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMakeMetaInfo
+{
+ bool readLibtoolFile(const QString &f);
+ bool readPkgCfgFile(const QString &f);
+ QMap<QString, QStringList> vars;
+ QString meta_type;
+ static QMap<QString, QMap<QString, QStringList> > cache_vars;
+ void clear();
+public:
+ QMakeMetaInfo();
+
+ bool readLib(QString lib);
+ static QString findLib(QString lib);
+ static bool libExists(QString lib);
+ QString type() const;
+
+ bool isEmpty(const QString &v);
+ QStringList &values(const QString &v);
+ QString first(const QString &v);
+ QMap<QString, QStringList> &variables();
+};
+
+inline bool QMakeMetaInfo::isEmpty(const QString &v)
+{ return !vars.contains(v) || vars[v].isEmpty(); }
+
+inline QString QMakeMetaInfo::type() const
+{ return meta_type; }
+
+inline QStringList &QMakeMetaInfo::values(const QString &v)
+{ return vars[v]; }
+
+inline QString QMakeMetaInfo::first(const QString &v)
+{
+#if defined(Q_CC_SUN) && (__SUNPRO_CC == 0x500) || defined(Q_CC_HP)
+ // workaround for Sun WorkShop 5.0 bug fixed in Forte 6
+ if (isEmpty(v))
+ return QString("");
+ else
+ return vars[v].first();
+#else
+ return isEmpty(v) ? QString("") : vars[v].first();
+#endif
+}
+
+inline QMap<QString, QStringList> &QMakeMetaInfo::variables()
+{ return vars; }
+
+inline bool QMakeMetaInfo::libExists(QString lib)
+{ return !findLib(lib).isNull(); }
+
+QT_END_NAMESPACE
+
+#endif // META_H
diff --git a/qmake/option.cpp b/qmake/option.cpp
new file mode 100644
index 0000000000..dd283365f2
--- /dev/null
+++ b/qmake/option.cpp
@@ -0,0 +1,813 @@
+/****************************************************************************
+**
+** 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 "option.h"
+#include "cachekeys.h"
+#include <qdir.h>
+#include <qregexp.h>
+#include <qhash.h>
+#include <qdebug.h>
+#include <qsettings.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+QT_BEGIN_NAMESPACE
+
+//convenience
+const char *Option::application_argv0 = 0;
+QString Option::prf_ext;
+QString Option::js_ext;
+QString Option::prl_ext;
+QString Option::libtool_ext;
+QString Option::pkgcfg_ext;
+QString Option::ui_ext;
+QStringList Option::h_ext;
+QString Option::cpp_moc_ext;
+QString Option::h_moc_ext;
+QStringList Option::cpp_ext;
+QStringList Option::c_ext;
+QString Option::obj_ext;
+QString Option::lex_ext;
+QString Option::yacc_ext;
+QString Option::pro_ext;
+QString Option::mmp_ext;
+QString Option::dir_sep;
+QString Option::dirlist_sep;
+QString Option::h_moc_mod;
+QString Option::cpp_moc_mod;
+QString Option::yacc_mod;
+QString Option::lex_mod;
+QString Option::sysenv_mod;
+QString Option::res_ext;
+char Option::field_sep;
+
+//mode
+Option::QMAKE_MODE Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING;
+
+//all modes
+QString Option::qmake_abslocation;
+int Option::warn_level = WarnLogic | WarnDeprecated;
+int Option::debug_level = 0;
+QFile Option::output;
+QString Option::output_dir;
+Option::QMAKE_RECURSIVE Option::recursive = Option::QMAKE_RECURSIVE_DEFAULT;
+QStringList Option::before_user_vars;
+QStringList Option::after_user_vars;
+QStringList Option::user_configs;
+QStringList Option::after_user_configs;
+QString Option::user_template;
+QString Option::user_template_prefix;
+QStringList Option::shellPath;
+Option::HOST_MODE Option::host_mode = Option::HOST_UNKNOWN_MODE;
+Option::TARG_MODE Option::target_mode = Option::TARG_UNKNOWN_MODE;
+bool Option::target_mode_overridden = false;
+
+//QMAKE_*_PROPERTY stuff
+QStringList Option::prop::properties;
+
+//QMAKE_GENERATE_PROJECT stuff
+bool Option::projfile::do_pwd = true;
+QStringList Option::projfile::project_dirs;
+
+//QMAKE_GENERATE_MAKEFILE stuff
+QString Option::mkfile::qmakespec;
+int Option::mkfile::cachefile_depth = -1;
+bool Option::mkfile::do_deps = true;
+bool Option::mkfile::do_mocs = true;
+bool Option::mkfile::do_dep_heuristics = true;
+bool Option::mkfile::do_preprocess = false;
+bool Option::mkfile::do_stub_makefile = false;
+bool Option::mkfile::do_cache = true;
+QString Option::mkfile::cachefile;
+QStringList Option::mkfile::project_files;
+QString Option::mkfile::qmakespec_commandline;
+
+static Option::QMAKE_MODE default_mode(QString progname)
+{
+ int s = progname.lastIndexOf(QDir::separator());
+ if(s != -1)
+ progname = progname.right(progname.length() - (s + 1));
+ if(progname == "qmakegen")
+ return Option::QMAKE_GENERATE_PROJECT;
+ else if(progname == "qt-config")
+ return Option::QMAKE_QUERY_PROPERTY;
+ return Option::QMAKE_GENERATE_MAKEFILE;
+}
+
+static QString detectProjectFile(const QString &path)
+{
+ QString ret;
+ QDir dir(path);
+ if(dir.exists(dir.dirName() + Option::pro_ext)) {
+ ret = dir.filePath(dir.dirName()) + Option::pro_ext;
+ } else { //last try..
+ QStringList profiles = dir.entryList(QStringList("*" + Option::pro_ext));
+ if(profiles.count() == 1)
+ ret = dir.filePath(profiles.at(0));
+ }
+ return ret;
+}
+
+QString project_builtin_regx();
+bool usage(const char *a0)
+{
+ fprintf(stdout, "Usage: %s [mode] [options] [files]\n"
+ "\n"
+ "QMake has two modes, one mode for generating project files based on\n"
+ "some heuristics, and the other for generating makefiles. Normally you\n"
+ "shouldn't need to specify a mode, as makefile generation is the default\n"
+ "mode for qmake, but you may use this to test qmake on an existing project\n"
+ "\n"
+ "Mode:\n"
+ " -project Put qmake into project file generation mode%s\n"
+ " In this mode qmake interprets files as files to\n"
+ " be built,\n"
+ " defaults to %s\n"
+ " Note: The created .pro file probably will \n"
+ " need to be edited. For example add the QT variable to \n"
+ " specify what modules are required.\n"
+ " -makefile Put qmake into makefile generation mode%s\n"
+ " In this mode qmake interprets files as project files to\n"
+ " be processed, if skipped qmake will try to find a project\n"
+ " file in your current working directory\n"
+ "\n"
+ "Warnings Options:\n"
+ " -Wnone Turn off all warnings; specific ones may be re-enabled by\n"
+ " later -W options\n"
+ " -Wall Turn on all warnings\n"
+ " -Wparser Turn on parser warnings\n"
+ " -Wlogic Turn on logic warnings (on by default)\n"
+ " -Wdeprecated Turn on deprecation warnings (on by default)\n"
+ "\n"
+ "Options:\n"
+ " * You can place any variable assignment in options and it will be *\n"
+ " * processed as if it was in [files]. These assignments will be parsed *\n"
+ " * before [files]. *\n"
+ " -o file Write output to file\n"
+ " -d Increase debug level\n"
+ " -t templ Overrides TEMPLATE as templ\n"
+ " -tp prefix Overrides TEMPLATE so that prefix is prefixed into the value\n"
+ " -help This help\n"
+ " -v Version information\n"
+ " -after All variable assignments after this will be\n"
+ " parsed after [files]\n"
+ " -norecursive Don't do a recursive search\n"
+ " -recursive Do a recursive search\n"
+ " -set <prop> <value> Set persistent property\n"
+ " -unset <prop> Unset persistent property\n"
+ " -query <prop> Query persistent property. Show all if <prop> is empty.\n"
+ " -cache file Use file as cache [makefile mode only]\n"
+ " -spec spec Use spec as QMAKESPEC [makefile mode only]\n"
+ " -nocache Don't use a cache file [makefile mode only]\n"
+ " -nodepend Don't generate dependencies [makefile mode only]\n"
+ " -nomoc Don't generate moc targets [makefile mode only]\n"
+ " -nopwd Don't look for files in pwd [project mode only]\n"
+ ,a0,
+ default_mode(a0) == Option::QMAKE_GENERATE_PROJECT ? " (default)" : "", project_builtin_regx().toLatin1().constData(),
+ default_mode(a0) == Option::QMAKE_GENERATE_MAKEFILE ? " (default)" : ""
+ );
+ return false;
+}
+
+int
+Option::parseCommandLine(int argc, char **argv, int skip)
+{
+ bool before = true;
+ for(int x = skip; x < argc; x++) {
+ if(*argv[x] == '-' && strlen(argv[x]) > 1) { /* options */
+ QString opt = argv[x] + 1;
+
+ //first param is a mode, or we default
+ if(x == 1) {
+ bool specified = true;
+ if(opt == "project") {
+ Option::recursive = Option::QMAKE_RECURSIVE_YES;
+ Option::qmake_mode = Option::QMAKE_GENERATE_PROJECT;
+ } else if(opt == "prl") {
+ Option::mkfile::do_deps = false;
+ Option::mkfile::do_mocs = false;
+ Option::qmake_mode = Option::QMAKE_GENERATE_PRL;
+ } else if(opt == "set") {
+ Option::qmake_mode = Option::QMAKE_SET_PROPERTY;
+ } else if(opt == "unset") {
+ Option::qmake_mode = Option::QMAKE_UNSET_PROPERTY;
+ } else if(opt == "query") {
+ Option::qmake_mode = Option::QMAKE_QUERY_PROPERTY;
+ } else if(opt == "makefile") {
+ Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
+ } else {
+ specified = false;
+ }
+ if(specified)
+ continue;
+ }
+ //all modes
+ if(opt == "o" || opt == "output") {
+ Option::output.setFileName(argv[++x]);
+ } else if(opt == "after") {
+ before = false;
+ } else if(opt == "t" || opt == "template") {
+ Option::user_template = argv[++x];
+ } else if(opt == "tp" || opt == "template_prefix") {
+ Option::user_template_prefix = argv[++x];
+ } else if(opt == "macx") {
+ fprintf(stderr, "-macx is deprecated.\n");
+ Option::host_mode = HOST_MACX_MODE;
+ Option::target_mode = TARG_MACX_MODE;
+ Option::target_mode_overridden = true;
+ } else if(opt == "unix") {
+ fprintf(stderr, "-unix is deprecated.\n");
+ Option::host_mode = HOST_UNIX_MODE;
+ Option::target_mode = TARG_UNIX_MODE;
+ Option::target_mode_overridden = true;
+ } else if(opt == "win32") {
+ fprintf(stderr, "-win32 is deprecated.\n");
+ Option::host_mode = HOST_WIN_MODE;
+ Option::target_mode = TARG_WIN_MODE;
+ Option::target_mode_overridden = true;
+ } else if(opt == "integrity") {
+ Option::target_mode = TARG_INTEGRITY_MODE;
+ } else if(opt == "d") {
+ Option::debug_level++;
+ } else if(opt == "version" || opt == "v" || opt == "-version") {
+ fprintf(stdout,
+ "QMake version %s\n"
+ "Using Qt version %s in %s\n",
+ qmake_version(), QT_VERSION_STR,
+ QLibraryInfo::location(QLibraryInfo::LibrariesPath).toLatin1().constData());
+#ifdef QMAKE_OPENSOURCE_VERSION
+ fprintf(stdout, "QMake is Open Source software from Nokia Corporation and/or its subsidiary(-ies).\n");
+#endif
+ return Option::QMAKE_CMDLINE_BAIL;
+ } else if(opt == "h" || opt == "help") {
+ return Option::QMAKE_CMDLINE_SHOW_USAGE;
+ } else if(opt == "Wall") {
+ Option::warn_level |= WarnAll;
+ } else if(opt == "Wparser") {
+ Option::warn_level |= WarnParser;
+ } else if(opt == "Wlogic") {
+ Option::warn_level |= WarnLogic;
+ } else if(opt == "Wdeprecated") {
+ Option::warn_level |= WarnDeprecated;
+ } else if(opt == "Wnone") {
+ Option::warn_level = WarnNone;
+ } else if(opt == "r" || opt == "recursive") {
+ Option::recursive = Option::QMAKE_RECURSIVE_YES;
+ } else if(opt == "nr" || opt == "norecursive") {
+ Option::recursive = Option::QMAKE_RECURSIVE_NO;
+ } else if(opt == "config") {
+ Option::user_configs += argv[++x];
+ } else {
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+ Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
+ if(opt == "nodepend" || opt == "nodepends") {
+ Option::mkfile::do_deps = false;
+ } else if(opt == "nomoc") {
+ Option::mkfile::do_mocs = false;
+ } else if(opt == "nocache") {
+ Option::mkfile::do_cache = false;
+ } else if(opt == "createstub") {
+ Option::mkfile::do_stub_makefile = true;
+ } else if(opt == "nodependheuristics") {
+ Option::mkfile::do_dep_heuristics = false;
+ } else if(opt == "E") {
+ fprintf(stderr, "-E is deprecated. Use -d instead.\n");
+ Option::mkfile::do_preprocess = true;
+ } else if(opt == "cache") {
+ Option::mkfile::cachefile = argv[++x];
+ } else if(opt == "platform" || opt == "spec") {
+ Option::mkfile::qmakespec = argv[++x];
+ Option::mkfile::qmakespec_commandline = argv[x];
+ } else {
+ fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
+ return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
+ }
+ } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
+ if(opt == "nopwd") {
+ Option::projfile::do_pwd = false;
+ } else {
+ fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
+ return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
+ }
+ }
+ }
+ } else {
+ QString arg = argv[x];
+ if(arg.indexOf('=') != -1) {
+ if(before)
+ Option::before_user_vars.append(arg);
+ else
+ Option::after_user_vars.append(arg);
+ } else {
+ bool handled = true;
+ if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY ||
+ Option::qmake_mode == Option::QMAKE_SET_PROPERTY ||
+ Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY) {
+ Option::prop::properties.append(arg);
+ } else {
+ QFileInfo fi(arg);
+ if(!fi.makeAbsolute()) //strange
+ arg = fi.filePath();
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+ Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
+ if(fi.isDir()) {
+ QString proj = detectProjectFile(arg);
+ if (!proj.isNull())
+ arg = proj;
+ }
+ Option::mkfile::project_files.append(arg);
+ } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
+ Option::projfile::project_dirs.append(arg);
+ } else {
+ handled = false;
+ }
+ }
+ if(!handled) {
+ return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
+ }
+ }
+ }
+ }
+
+ return Option::QMAKE_CMDLINE_SUCCESS;
+}
+
+#ifdef Q_OS_WIN
+static QStringList detectShellPath()
+{
+ QStringList paths;
+ QString path = qgetenv("PATH");
+ QStringList pathlist = path.toLower().split(";");
+ for (int i = 0; i < pathlist.count(); i++) {
+ QString maybeSh = pathlist.at(i) + "/sh.exe";
+ if (QFile::exists(maybeSh)) {
+ paths.append(maybeSh);
+ }
+ }
+ return paths;
+}
+#endif
+
+int
+Option::init(int argc, char **argv)
+{
+ Option::application_argv0 = 0;
+ Option::cpp_moc_mod = "";
+ Option::h_moc_mod = "moc_";
+ Option::lex_mod = "_lex";
+ Option::yacc_mod = "_yacc";
+ Option::prl_ext = ".prl";
+ Option::libtool_ext = ".la";
+ Option::pkgcfg_ext = ".pc";
+ Option::prf_ext = ".prf";
+ Option::js_ext = ".js";
+ Option::ui_ext = ".ui";
+ Option::h_ext << ".h" << ".hpp" << ".hh" << ".hxx";
+ Option::c_ext << ".c";
+#ifndef Q_OS_WIN
+ Option::h_ext << ".H";
+#endif
+ Option::cpp_moc_ext = ".moc";
+ Option::h_moc_ext = ".cpp";
+ Option::cpp_ext << ".cpp" << ".cc" << ".cxx";
+#ifndef Q_OS_WIN
+ Option::cpp_ext << ".C";
+#endif
+ Option::lex_ext = ".l";
+ Option::yacc_ext = ".y";
+ Option::pro_ext = ".pro";
+ Option::mmp_ext = ".mmp";
+#ifdef Q_OS_WIN
+ Option::dirlist_sep = ";";
+ Option::shellPath = detectShellPath();
+ Option::res_ext = ".res";
+#else
+ Option::dirlist_sep = ":";
+ Option::shellPath = QStringList("sh");
+#endif
+ Option::sysenv_mod = "QMAKE_ENV_";
+ Option::field_sep = ' ';
+
+ if(argc && argv) {
+ Option::application_argv0 = argv[0];
+ QString argv0 = argv[0];
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
+ Option::qmake_mode = default_mode(argv0);
+ if(!argv0.isEmpty() && !QFileInfo(argv0).isRelative()) {
+ Option::qmake_abslocation = argv0;
+ } else if (argv0.contains(QLatin1Char('/'))
+#ifdef Q_OS_WIN
+ || argv0.contains(QLatin1Char('\\'))
+#endif
+ ) { //relative PWD
+ Option::qmake_abslocation = QDir::current().absoluteFilePath(argv0);
+ } else { //in the PATH
+ QByteArray pEnv = qgetenv("PATH");
+ QDir currentDir = QDir::current();
+#ifdef Q_OS_WIN
+ QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(";"));
+#else
+ QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":"));
+#endif
+ for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
+ if ((*p).isEmpty())
+ continue;
+ QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
+#ifdef Q_OS_WIN
+ candidate += ".exe";
+#endif
+ if (QFile::exists(candidate)) {
+ Option::qmake_abslocation = candidate;
+ break;
+ }
+ }
+ }
+ if(!Option::qmake_abslocation.isNull())
+ Option::qmake_abslocation = QDir::cleanPath(Option::qmake_abslocation);
+ } else {
+ Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
+ }
+
+ const QByteArray envflags = qgetenv("QMAKEFLAGS");
+ if (!envflags.isNull()) {
+ int env_argc = 0, env_size = 0, currlen=0;
+ char quote = 0, **env_argv = NULL;
+ for (int i = 0; i < envflags.size(); ++i) {
+ if (!quote && (envflags.at(i) == '\'' || envflags.at(i) == '"')) {
+ quote = envflags.at(i);
+ } else if (envflags.at(i) == quote) {
+ quote = 0;
+ } else if (!quote && envflags.at(i) == ' ') {
+ if (currlen && env_argv && env_argv[env_argc]) {
+ env_argv[env_argc][currlen] = '\0';
+ currlen = 0;
+ env_argc++;
+ }
+ } else {
+ if(!env_argv || env_argc > env_size) {
+ env_argv = (char **)realloc(env_argv, sizeof(char *)*(env_size+=10));
+ for(int i2 = env_argc; i2 < env_size; i2++)
+ env_argv[i2] = NULL;
+ }
+ if(!env_argv[env_argc]) {
+ currlen = 0;
+ env_argv[env_argc] = (char*)malloc(255);
+ }
+ if(currlen < 255)
+ env_argv[env_argc][currlen++] = envflags.at(i);
+ }
+ }
+ if(env_argv) {
+ if(env_argv[env_argc]) {
+ env_argv[env_argc][currlen] = '\0';
+ currlen = 0;
+ env_argc++;
+ }
+ parseCommandLine(env_argc, env_argv);
+ for(int i2 = 0; i2 < env_size; i2++) {
+ if(env_argv[i2])
+ free(env_argv[i2]);
+ }
+ free(env_argv);
+ }
+ }
+ if(argc && argv) {
+ int ret = parseCommandLine(argc, argv, 1);
+ if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
+ if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0)
+ usage(argv[0]);
+ return ret;
+ //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false;
+ }
+ }
+
+ //last chance for defaults
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+ Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
+ if(Option::mkfile::qmakespec.isNull() || Option::mkfile::qmakespec.isEmpty())
+ Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData());
+
+ //try REALLY hard to do it for them, lazy..
+ if(Option::mkfile::project_files.isEmpty()) {
+ QString proj = detectProjectFile(qmake_getpwd());
+ if(!proj.isNull())
+ Option::mkfile::project_files.append(proj);
+#ifndef QT_BUILD_QMAKE_LIBRARY
+ if(Option::mkfile::project_files.isEmpty()) {
+ usage(argv[0]);
+ return Option::QMAKE_CMDLINE_ERROR;
+ }
+#endif
+ }
+ } else if (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
+#if defined(Q_OS_MAC)
+ Option::host_mode = Option::HOST_MACX_MODE;
+ Option::target_mode = Option::TARG_MACX_MODE;
+#elif defined(Q_OS_UNIX)
+ Option::host_mode = Option::HOST_UNIX_MODE;
+ Option::target_mode = Option::TARG_UNIX_MODE;
+#else
+ Option::host_mode = Option::HOST_WIN_MODE;
+ Option::target_mode = Option::TARG_WIN_MODE;
+#endif
+ }
+
+ //defaults for globals
+ if (Option::host_mode != Option::HOST_UNKNOWN_MODE)
+ applyHostMode();
+ return QMAKE_CMDLINE_SUCCESS;
+}
+
+void Option::applyHostMode()
+{
+ if (Option::host_mode == Option::HOST_WIN_MODE) {
+ Option::dir_sep = "\\";
+ Option::obj_ext = ".obj";
+ } else {
+ Option::dir_sep = "/";
+ Option::obj_ext = ".o";
+ }
+}
+
+bool Option::postProcessProject(QMakeProject *project)
+{
+ Option::cpp_ext = project->variables()["QMAKE_EXT_CPP"];
+ if(cpp_ext.isEmpty())
+ cpp_ext << ".cpp"; //something must be there
+ Option::h_ext = project->variables()["QMAKE_EXT_H"];
+ if(h_ext.isEmpty())
+ h_ext << ".h";
+ Option::c_ext = project->variables()["QMAKE_EXT_C"];
+ if(c_ext.isEmpty())
+ c_ext << ".c"; //something must be there
+
+ if(!project->isEmpty("QMAKE_EXT_RES"))
+ Option::res_ext = project->first("QMAKE_EXT_RES");
+ if(!project->isEmpty("QMAKE_EXT_PKGCONFIG"))
+ Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG");
+ if(!project->isEmpty("QMAKE_EXT_LIBTOOL"))
+ Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL");
+ if(!project->isEmpty("QMAKE_EXT_PRL"))
+ Option::prl_ext = project->first("QMAKE_EXT_PRL");
+ if(!project->isEmpty("QMAKE_EXT_PRF"))
+ Option::prf_ext = project->first("QMAKE_EXT_PRF");
+ if(!project->isEmpty("QMAKE_EXT_JS"))
+ Option::prf_ext = project->first("QMAKE_EXT_JS");
+ if(!project->isEmpty("QMAKE_EXT_UI"))
+ Option::ui_ext = project->first("QMAKE_EXT_UI");
+ if(!project->isEmpty("QMAKE_EXT_CPP_MOC"))
+ Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC");
+ if(!project->isEmpty("QMAKE_EXT_H_MOC"))
+ Option::h_moc_ext = project->first("QMAKE_EXT_H_MOC");
+ if(!project->isEmpty("QMAKE_EXT_LEX"))
+ Option::lex_ext = project->first("QMAKE_EXT_LEX");
+ if(!project->isEmpty("QMAKE_EXT_YACC"))
+ Option::yacc_ext = project->first("QMAKE_EXT_YACC");
+ if(!project->isEmpty("QMAKE_EXT_OBJ"))
+ Option::obj_ext = project->first("QMAKE_EXT_OBJ");
+ if(!project->isEmpty("QMAKE_H_MOD_MOC"))
+ Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC");
+ if(!project->isEmpty("QMAKE_CPP_MOD_MOC"))
+ Option::cpp_moc_mod = project->first("QMAKE_CPP_MOD_MOC");
+ if(!project->isEmpty("QMAKE_MOD_LEX"))
+ Option::lex_mod = project->first("QMAKE_MOD_LEX");
+ if(!project->isEmpty("QMAKE_MOD_YACC"))
+ Option::yacc_mod = project->first("QMAKE_MOD_YACC");
+ if(!project->isEmpty("QMAKE_DIR_SEP"))
+ Option::dir_sep = project->first("QMAKE_DIR_SEP");
+ if(!project->isEmpty("QMAKE_DIRLIST_SEP"))
+ Option::dirlist_sep = project->first("QMAKE_DIRLIST_SEP");
+ if(!project->isEmpty("QMAKE_MOD_SYSTEM_ENV"))
+ Option::sysenv_mod = project->first("QMAKE_MOD_SYSTEM_ENV");
+ return true;
+}
+
+QString
+Option::fixString(QString string, uchar flags)
+{
+ //const QString orig_string = string;
+ static QHash<FixStringCacheKey, QString> *cache = 0;
+ if(!cache) {
+ cache = new QHash<FixStringCacheKey, QString>;
+ qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache);
+ }
+ FixStringCacheKey cacheKey(string, flags);
+
+ QHash<FixStringCacheKey, QString>::const_iterator it = cache->constFind(cacheKey);
+
+ if (it != cache->constEnd()) {
+ //qDebug() << "Fix (cached) " << orig_string << "->" << it.value();
+ return it.value();
+ }
+
+ //fix the environment variables
+ if(flags & Option::FixEnvVars) {
+ int rep;
+ static QRegExp reg_var("\\$\\(.*\\)");
+ reg_var.setMinimal(true);
+ while((rep = reg_var.indexIn(string)) != -1)
+ string.replace(rep, reg_var.matchedLength(),
+ QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
+ }
+
+ //canonicalize it (and treat as a path)
+ if(flags & Option::FixPathCanonicalize) {
+#if 0
+ string = QFileInfo(string).canonicalFilePath();
+#endif
+ string = QDir::cleanPath(string);
+ }
+
+ if(string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':'))
+ string[0] = string[0].toLower();
+
+ //fix separators
+ Q_ASSERT(!((flags & Option::FixPathToLocalSeparators) && (flags & Option::FixPathToTargetSeparators)));
+ if(flags & Option::FixPathToLocalSeparators) {
+#if defined(Q_OS_WIN32)
+ string = string.replace('/', '\\');
+#else
+ string = string.replace('\\', '/');
+#endif
+ } else if(flags & Option::FixPathToTargetSeparators) {
+ string = string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep);
+ }
+
+ if ((string.startsWith("\"") && string.endsWith("\"")) ||
+ (string.startsWith("\'") && string.endsWith("\'")))
+ string = string.mid(1, string.length()-2);
+
+ //cache
+ //qDebug() << "Fix" << orig_string << "->" << string;
+ cache->insert(cacheKey, string);
+ return string;
+}
+
+const char *qmake_version()
+{
+ static char *ret = NULL;
+ if(ret)
+ return ret;
+ ret = (char *)malloc(15);
+ qmakeAddCacheClear(qmakeFreeCacheClear, (void**)&ret);
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ sprintf_s(ret, 15, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
+#else
+ sprintf(ret, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
+#endif
+ return ret;
+}
+
+void debug_msg_internal(int level, const char *fmt, ...)
+{
+ if(Option::debug_level < level)
+ return;
+ fprintf(stderr, "DEBUG %d: ", level);
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+ fprintf(stderr, "\n");
+}
+
+void warn_msg(QMakeWarn type, const char *fmt, ...)
+{
+ if(!(Option::warn_level & type))
+ return;
+ fprintf(stderr, "WARNING: ");
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+ fprintf(stderr, "\n");
+}
+
+class QMakeCacheClearItem {
+private:
+ qmakeCacheClearFunc func;
+ void **data;
+public:
+ QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { }
+ ~QMakeCacheClearItem() {
+ (*func)(*data);
+ *data = 0;
+ }
+};
+static QList<QMakeCacheClearItem*> cache_items;
+
+void
+qmakeClearCaches()
+{
+ qDeleteAll(cache_items);
+ cache_items.clear();
+}
+
+void
+qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
+{
+ cache_items.append(new QMakeCacheClearItem(func, data));
+}
+
+#ifdef Q_OS_WIN
+# include <windows.h>
+
+QT_USE_NAMESPACE
+#endif
+
+QString qmake_libraryInfoFile()
+{
+ QString ret;
+#if defined( Q_OS_WIN )
+ wchar_t module_name[MAX_PATH];
+ GetModuleFileName(0, module_name, MAX_PATH);
+ QFileInfo filePath = QString::fromWCharArray(module_name);
+ ret = filePath.filePath();
+#else
+ QString argv0 = QFile::decodeName(QByteArray(Option::application_argv0));
+ QString absPath;
+
+ if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) {
+ /*
+ If argv0 starts with a slash, it is already an absolute
+ file path.
+ */
+ absPath = argv0;
+ } else if (argv0.contains(QLatin1Char('/'))) {
+ /*
+ If argv0 contains one or more slashes, it is a file path
+ relative to the current directory.
+ */
+ absPath = QDir::current().absoluteFilePath(argv0);
+ } else {
+ /*
+ Otherwise, the file path has to be determined using the
+ PATH environment variable.
+ */
+ QByteArray pEnv = qgetenv("PATH");
+ QDir currentDir = QDir::current();
+ QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1String(":"));
+ for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
+ if ((*p).isEmpty())
+ continue;
+ QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
+ QFileInfo candidate_fi(candidate);
+ if (candidate_fi.exists() && !candidate_fi.isDir()) {
+ absPath = candidate;
+ break;
+ }
+ }
+ }
+
+ absPath = QDir::cleanPath(absPath);
+
+ QFileInfo fi(absPath);
+ ret = fi.exists() ? fi.canonicalFilePath() : QString();
+#endif
+ if(!ret.isEmpty())
+ ret = QDir(QFileInfo(ret).absolutePath()).filePath("qt.conf");
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/option.h b/qmake/option.h
new file mode 100644
index 0000000000..e17ce5a3a0
--- /dev/null
+++ b/qmake/option.h
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** 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 OPTION_H
+#define OPTION_H
+
+#include "project.h"
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QMAKE_VERSION_MAJOR 2
+#define QMAKE_VERSION_MINOR 1
+#define QMAKE_VERSION_PATCH 0
+const char *qmake_version();
+
+QString qmake_getpwd();
+bool qmake_setpwd(const QString &p);
+
+#define debug_msg if(Option::debug_level) debug_msg_internal
+void debug_msg_internal(int level, const char *fmt, ...); //don't call directly, use debug_msg
+enum QMakeWarn {
+ WarnNone = 0x00,
+ WarnParser = 0x01,
+ WarnLogic = 0x02,
+ WarnDeprecated = 0x04,
+ WarnAll = 0xFF
+};
+void warn_msg(QMakeWarn t, const char *fmt, ...);
+
+struct Option
+{
+ //simply global convenience
+ static QString js_ext;
+ static QString libtool_ext;
+ static QString pkgcfg_ext;
+ static QString prf_ext;
+ static QString prl_ext;
+ static QString ui_ext;
+ static QStringList h_ext;
+ static QStringList cpp_ext;
+ static QStringList c_ext;
+ static QString h_moc_ext;
+ static QString cpp_moc_ext;
+ static QString obj_ext;
+ static QString lex_ext;
+ static QString yacc_ext;
+ static QString h_moc_mod;
+ static QString cpp_moc_mod;
+ static QString lex_mod;
+ static QString yacc_mod;
+ static QString dir_sep;
+ static QString dirlist_sep;
+ static QString sysenv_mod;
+ static QString pro_ext;
+ static QString mmp_ext;
+ static QString res_ext;
+ static char field_sep;
+ static const char *application_argv0;
+
+ enum CmdLineFlags {
+ QMAKE_CMDLINE_SUCCESS = 0x00,
+ QMAKE_CMDLINE_SHOW_USAGE = 0x01,
+ QMAKE_CMDLINE_BAIL = 0x02,
+ QMAKE_CMDLINE_ERROR = 0x04
+ };
+
+ //both of these must be called..
+ static int init(int argc=0, char **argv=0); //parse cmdline
+ static void applyHostMode();
+ static bool postProcessProject(QMakeProject *);
+
+ enum StringFixFlags {
+ FixNone = 0x00,
+ FixEnvVars = 0x01,
+ FixPathCanonicalize = 0x02,
+ FixPathToLocalSeparators = 0x04,
+ FixPathToTargetSeparators = 0x08
+ };
+ static QString fixString(QString string, uchar flags);
+
+ //and convenience functions
+ inline static QString fixPathToLocalOS(const QString &in, bool fix_env=true, bool canonical=true)
+ {
+ uchar flags = FixPathToLocalSeparators;
+ if(fix_env)
+ flags |= FixEnvVars;
+ if(canonical)
+ flags |= FixPathCanonicalize;
+ return fixString(in, flags);
+ }
+ inline static QString fixPathToTargetOS(const QString &in, bool fix_env=true, bool canonical=true)
+ {
+ uchar flags = FixPathToTargetSeparators;
+ if(fix_env)
+ flags |= FixEnvVars;
+ if(canonical)
+ flags |= FixPathCanonicalize;
+ return fixString(in, flags);
+ }
+
+ inline static bool hasFileExtension(const QString &str, const QStringList &extensions)
+ {
+ foreach (const QString &ext, extensions)
+ if (str.endsWith(ext))
+ return true;
+ return false;
+ }
+
+ //global qmake mode, can only be in one mode per invocation!
+ enum QMAKE_MODE { QMAKE_GENERATE_NOTHING,
+ QMAKE_GENERATE_PROJECT, QMAKE_GENERATE_MAKEFILE, QMAKE_GENERATE_PRL,
+ QMAKE_SET_PROPERTY, QMAKE_UNSET_PROPERTY, QMAKE_QUERY_PROPERTY };
+ static QMAKE_MODE qmake_mode;
+
+ //all modes
+ static QString qmake_abslocation;
+ static QFile output;
+ static QString output_dir;
+ static int debug_level;
+ static int warn_level;
+ enum QMAKE_RECURSIVE { QMAKE_RECURSIVE_DEFAULT, QMAKE_RECURSIVE_YES, QMAKE_RECURSIVE_NO };
+ static QMAKE_RECURSIVE recursive;
+ static QStringList before_user_vars, after_user_vars, user_configs, after_user_configs;
+ enum HOST_MODE { HOST_UNKNOWN_MODE, HOST_UNIX_MODE, HOST_WIN_MODE, HOST_MACX_MODE };
+ static HOST_MODE host_mode;
+ enum TARG_MODE { TARG_UNKNOWN_MODE, TARG_UNIX_MODE, TARG_WIN_MODE, TARG_MACX_MODE,
+ TARG_SYMBIAN_MODE, TARG_INTEGRITY_MODE };
+ static TARG_MODE target_mode;
+ static bool target_mode_overridden;
+ static QString user_template, user_template_prefix;
+ static QStringList shellPath;
+
+ //QMAKE_*_PROPERTY options
+ struct prop {
+ static QStringList properties;
+ };
+
+ //QMAKE_GENERATE_PROJECT options
+ struct projfile {
+ static bool do_pwd;
+ static QStringList project_dirs;
+ };
+
+ //QMAKE_GENERATE_MAKEFILE options
+ struct mkfile {
+ static QString qmakespec;
+ static bool do_cache;
+ static bool do_deps;
+ static bool do_mocs;
+ static bool do_dep_heuristics;
+ static bool do_preprocess;
+ static bool do_stub_makefile;
+ static QString cachefile;
+ static int cachefile_depth;
+ static QStringList project_files;
+ static QString qmakespec_commandline;
+ };
+
+private:
+ static int parseCommandLine(int, char **, int=0);
+};
+
+inline QString fixEnvVariables(const QString &x) { return Option::fixString(x, Option::FixEnvVars); }
+inline QStringList splitPathList(const QString &paths) { return paths.split(Option::dirlist_sep); }
+
+// this is a stripped down version of the one found in QtCore
+class QLibraryInfo
+{
+public:
+ enum LibraryLocation
+ {
+ PrefixPath,
+ DocumentationPath,
+ HeadersPath,
+ LibrariesPath,
+ BinariesPath,
+ PluginsPath,
+ DataPath,
+ TranslationsPath,
+ SettingsPath,
+ DemosPath,
+ ExamplesPath,
+ ImportsPath
+ };
+ static QString location(LibraryLocation);
+};
+
+QT_END_NAMESPACE
+
+#endif // OPTION_H
diff --git a/qmake/project.cpp b/qmake/project.cpp
new file mode 100644
index 0000000000..d4fa786ac5
--- /dev/null
+++ b/qmake/project.cpp
@@ -0,0 +1,3170 @@
+/****************************************************************************
+**
+** 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 "project.h"
+#include "property.h"
+#include "option.h"
+#include "cachekeys.h"
+#include "generators/metamakefile.h"
+
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+#include <qstack.h>
+#include <qhash.h>
+#include <qdebug.h>
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#include <sys/utsname.h>
+#elif defined(Q_OS_WIN32)
+#include <windows.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+
+// Included from tools/shared
+#include <symbian/epocroot_p.h>
+
+#ifdef Q_OS_WIN32
+#define QT_POPEN _popen
+#define QT_PCLOSE _pclose
+#else
+#define QT_POPEN popen
+#define QT_PCLOSE pclose
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//expand functions
+enum ExpandFunc { E_MEMBER=1, E_FIRST, E_LAST, E_CAT, E_FROMFILE, E_EVAL, E_LIST,
+ E_SPRINTF, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION,
+ E_FIND, E_SYSTEM, E_UNIQUE, E_QUOTE, E_ESCAPE_EXPAND,
+ E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE, E_REPLACE,
+ E_SIZE, E_GENERATE_UID };
+QMap<QString, ExpandFunc> qmake_expandFunctions()
+{
+ static QMap<QString, ExpandFunc> *qmake_expand_functions = 0;
+ if(!qmake_expand_functions) {
+ qmake_expand_functions = new QMap<QString, ExpandFunc>;
+ qmakeAddCacheClear(qmakeDeleteCacheClear<QMap<QString, ExpandFunc> >, (void**)&qmake_expand_functions);
+ qmake_expand_functions->insert("member", E_MEMBER);
+ qmake_expand_functions->insert("first", E_FIRST);
+ qmake_expand_functions->insert("last", E_LAST);
+ qmake_expand_functions->insert("cat", E_CAT);
+ qmake_expand_functions->insert("fromfile", E_FROMFILE);
+ qmake_expand_functions->insert("eval", E_EVAL);
+ qmake_expand_functions->insert("list", E_LIST);
+ qmake_expand_functions->insert("sprintf", E_SPRINTF);
+ qmake_expand_functions->insert("join", E_JOIN);
+ qmake_expand_functions->insert("split", E_SPLIT);
+ qmake_expand_functions->insert("basename", E_BASENAME);
+ qmake_expand_functions->insert("dirname", E_DIRNAME);
+ qmake_expand_functions->insert("section", E_SECTION);
+ qmake_expand_functions->insert("find", E_FIND);
+ qmake_expand_functions->insert("system", E_SYSTEM);
+ qmake_expand_functions->insert("unique", E_UNIQUE);
+ qmake_expand_functions->insert("quote", E_QUOTE);
+ qmake_expand_functions->insert("escape_expand", E_ESCAPE_EXPAND);
+ qmake_expand_functions->insert("upper", E_UPPER);
+ qmake_expand_functions->insert("lower", E_LOWER);
+ qmake_expand_functions->insert("re_escape", E_RE_ESCAPE);
+ qmake_expand_functions->insert("files", E_FILES);
+ qmake_expand_functions->insert("prompt", E_PROMPT);
+ qmake_expand_functions->insert("replace", E_REPLACE);
+ qmake_expand_functions->insert("size", E_SIZE);
+ qmake_expand_functions->insert("generate_uid", E_GENERATE_UID);
+ }
+ return *qmake_expand_functions;
+}
+//replace functions
+enum TestFunc { T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS,
+ T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM,
+ T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE,
+ T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_ERROR,
+ T_MESSAGE, T_WARNING, T_IF, T_OPTION };
+QMap<QString, TestFunc> qmake_testFunctions()
+{
+ static QMap<QString, TestFunc> *qmake_test_functions = 0;
+ if(!qmake_test_functions) {
+ qmake_test_functions = new QMap<QString, TestFunc>;
+ qmake_test_functions->insert("requires", T_REQUIRES);
+ qmake_test_functions->insert("greaterThan", T_GREATERTHAN);
+ qmake_test_functions->insert("lessThan", T_LESSTHAN);
+ qmake_test_functions->insert("equals", T_EQUALS);
+ qmake_test_functions->insert("isEqual", T_EQUALS);
+ qmake_test_functions->insert("exists", T_EXISTS);
+ qmake_test_functions->insert("export", T_EXPORT);
+ qmake_test_functions->insert("clear", T_CLEAR);
+ qmake_test_functions->insert("unset", T_UNSET);
+ qmake_test_functions->insert("eval", T_EVAL);
+ qmake_test_functions->insert("CONFIG", T_CONFIG);
+ qmake_test_functions->insert("if", T_IF);
+ qmake_test_functions->insert("isActiveConfig", T_CONFIG);
+ qmake_test_functions->insert("system", T_SYSTEM);
+ qmake_test_functions->insert("return", T_RETURN);
+ qmake_test_functions->insert("break", T_BREAK);
+ qmake_test_functions->insert("next", T_NEXT);
+ qmake_test_functions->insert("defined", T_DEFINED);
+ qmake_test_functions->insert("contains", T_CONTAINS);
+ qmake_test_functions->insert("infile", T_INFILE);
+ qmake_test_functions->insert("count", T_COUNT);
+ qmake_test_functions->insert("isEmpty", T_ISEMPTY);
+ qmake_test_functions->insert("include", T_INCLUDE);
+ qmake_test_functions->insert("load", T_LOAD);
+ qmake_test_functions->insert("debug", T_DEBUG);
+ qmake_test_functions->insert("error", T_ERROR);
+ qmake_test_functions->insert("message", T_MESSAGE);
+ qmake_test_functions->insert("warning", T_WARNING);
+ qmake_test_functions->insert("option", T_OPTION);
+ }
+ return *qmake_test_functions;
+}
+
+struct parser_info {
+ QString file;
+ int line_no;
+ bool from_file;
+} parser;
+
+static QString remove_quotes(const QString &arg)
+{
+ const ushort SINGLEQUOTE = '\'';
+ const ushort DOUBLEQUOTE = '"';
+
+ const QChar *arg_data = arg.data();
+ const ushort first = arg_data->unicode();
+ const int arg_len = arg.length();
+ if(first == SINGLEQUOTE || first == DOUBLEQUOTE) {
+ const ushort last = (arg_data+arg_len-1)->unicode();
+ if(last == first)
+ return arg.mid(1, arg_len-2);
+ }
+ return arg;
+}
+
+static QString varMap(const QString &x)
+{
+ QString ret(x);
+ if(ret == "INTERFACES")
+ ret = "FORMS";
+ else if(ret == "QMAKE_POST_BUILD")
+ ret = "QMAKE_POST_LINK";
+ else if(ret == "TARGETDEPS")
+ ret = "POST_TARGETDEPS";
+ else if(ret == "LIBPATH")
+ ret = "QMAKE_LIBDIR";
+ else if(ret == "QMAKE_EXT_MOC")
+ ret = "QMAKE_EXT_CPP_MOC";
+ else if(ret == "QMAKE_MOD_MOC")
+ ret = "QMAKE_H_MOD_MOC";
+ else if(ret == "QMAKE_LFLAGS_SHAPP")
+ ret = "QMAKE_LFLAGS_APP";
+ else if(ret == "PRECOMPH")
+ ret = "PRECOMPILED_HEADER";
+ else if(ret == "PRECOMPCPP")
+ ret = "PRECOMPILED_SOURCE";
+ else if(ret == "INCPATH")
+ ret = "INCLUDEPATH";
+ else if(ret == "QMAKE_EXTRA_WIN_COMPILERS" || ret == "QMAKE_EXTRA_UNIX_COMPILERS")
+ ret = "QMAKE_EXTRA_COMPILERS";
+ else if(ret == "QMAKE_EXTRA_WIN_TARGETS" || ret == "QMAKE_EXTRA_UNIX_TARGETS")
+ ret = "QMAKE_EXTRA_TARGETS";
+ else if(ret == "QMAKE_EXTRA_UNIX_INCLUDES")
+ ret = "QMAKE_EXTRA_INCLUDES";
+ else if(ret == "QMAKE_EXTRA_UNIX_VARIABLES")
+ ret = "QMAKE_EXTRA_VARIABLES";
+ else if(ret == "QMAKE_RPATH")
+ ret = "QMAKE_LFLAGS_RPATH";
+ else if(ret == "QMAKE_FRAMEWORKDIR")
+ ret = "QMAKE_FRAMEWORKPATH";
+ else if(ret == "QMAKE_FRAMEWORKDIR_FLAGS")
+ ret = "QMAKE_FRAMEWORKPATH_FLAGS";
+ else
+ return ret;
+ warn_msg(WarnDeprecated, "%s:%d: Variable %s is deprecated; use %s instead.",
+ parser.file.toLatin1().constData(), parser.line_no,
+ x.toLatin1().constData(), ret.toLatin1().constData());
+ return ret;
+}
+
+static QStringList split_arg_list(const QString &params)
+{
+ int quote = 0;
+ QStringList args;
+
+ const ushort LPAREN = '(';
+ const ushort RPAREN = ')';
+ const ushort SINGLEQUOTE = '\'';
+ const ushort DOUBLEQUOTE = '"';
+ const ushort BACKSLASH = '\\';
+ const ushort COMMA = ',';
+ const ushort SPACE = ' ';
+ //const ushort TAB = '\t';
+
+ const QChar *params_data = params.data();
+ const int params_len = params.length();
+ for(int last = 0; ;) {
+ while(last < params_len && (params_data[last].unicode() == SPACE
+ /*|| params_data[last].unicode() == TAB*/))
+ ++last;
+ for(int x = last, parens = 0; ; x++) {
+ if(x == params_len) {
+ while(x > last && params_data[x-1].unicode() == SPACE)
+ --x;
+ args << params.mid(last, x - last);
+ // Could do a check for unmatched parens here, but split_value_list()
+ // is called on all our output, so mistakes will be caught anyway.
+ return args;
+ }
+ ushort unicode = params_data[x].unicode();
+ if(x != (int)params_len-1 && unicode == BACKSLASH &&
+ (params_data[x+1].unicode() == SINGLEQUOTE || params_data[x+1].unicode() == DOUBLEQUOTE)) {
+ x++; //get that 'escape'
+ } else if(quote && unicode == quote) {
+ quote = 0;
+ } else if(!quote && (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE)) {
+ quote = unicode;
+ } else if(unicode == RPAREN) {
+ --parens;
+ } else if(unicode == LPAREN) {
+ ++parens;
+ }
+ if(!parens && !quote && unicode == COMMA) {
+ int prev = last;
+ last = x+1;
+ while(x > prev && params_data[x-1].unicode() == SPACE)
+ --x;
+ args << params.mid(prev, x - prev);
+ break;
+ }
+ }
+ }
+}
+
+static QStringList split_value_list(const QString &vals)
+{
+ QString build;
+ QStringList ret;
+ ushort quote = 0;
+ int parens = 0;
+
+ const ushort LPAREN = '(';
+ const ushort RPAREN = ')';
+ const ushort SINGLEQUOTE = '\'';
+ const ushort DOUBLEQUOTE = '"';
+ const ushort BACKSLASH = '\\';
+
+ ushort unicode;
+ const QChar *vals_data = vals.data();
+ const int vals_len = vals.length();
+ for(int x = 0; x < vals_len; x++) {
+ unicode = vals_data[x].unicode();
+ if(x != (int)vals_len-1 && unicode == BACKSLASH &&
+ (vals_data[x+1].unicode() == SINGLEQUOTE || vals_data[x+1].unicode() == DOUBLEQUOTE)) {
+ build += vals_data[x++]; //get that 'escape'
+ } else if(quote && unicode == quote) {
+ quote = 0;
+ } else if(!quote && (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE)) {
+ quote = unicode;
+ } else if(unicode == RPAREN) {
+ --parens;
+ } else if(unicode == LPAREN) {
+ ++parens;
+ }
+
+ if(!parens && !quote && (vals_data[x] == Option::field_sep)) {
+ ret << build;
+ build.clear();
+ } else {
+ build += vals_data[x];
+ }
+ }
+ if(!build.isEmpty())
+ ret << build;
+ if (parens)
+ warn_msg(WarnDeprecated, "%s:%d: Unmatched parentheses are deprecated.",
+ parser.file.toLatin1().constData(), parser.line_no);
+ // Could do a check for unmatched quotes here, but doVariableReplaceExpand()
+ // is called on all our output, so mistakes will be caught anyway.
+ return ret;
+}
+
+//just a parsable entity
+struct ParsableBlock
+{
+ ParsableBlock() : ref_cnt(1) { }
+ virtual ~ParsableBlock() { }
+
+ struct Parse {
+ QString text;
+ parser_info pi;
+ Parse(const QString &t) : text(t){ pi = parser; }
+ };
+ QList<Parse> parselist;
+
+ inline int ref() { return ++ref_cnt; }
+ inline int deref() { return --ref_cnt; }
+
+protected:
+ int ref_cnt;
+ virtual bool continueBlock() = 0;
+ bool eval(QMakeProject *p, QMap<QString, QStringList> &place);
+};
+
+bool ParsableBlock::eval(QMakeProject *p, QMap<QString, QStringList> &place)
+{
+ //save state
+ parser_info pi = parser;
+ const int block_count = p->scope_blocks.count();
+
+ //execute
+ bool ret = true;
+ for(int i = 0; i < parselist.count(); i++) {
+ parser = parselist.at(i).pi;
+ if(!(ret = p->parse(parselist.at(i).text, place)) || !continueBlock())
+ break;
+ }
+
+ //restore state
+ parser = pi;
+ while(p->scope_blocks.count() > block_count)
+ p->scope_blocks.pop();
+ return ret;
+}
+
+//defined functions
+struct FunctionBlock : public ParsableBlock
+{
+ FunctionBlock() : calling_place(0), scope_level(1), cause_return(false) { }
+
+ QMap<QString, QStringList> vars;
+ QMap<QString, QStringList> *calling_place;
+ QStringList return_value;
+ int scope_level;
+ bool cause_return;
+
+ bool exec(const QList<QStringList> &args,
+ QMakeProject *p, QMap<QString, QStringList> &place, QStringList &functionReturn);
+ virtual bool continueBlock() { return !cause_return; }
+};
+
+bool FunctionBlock::exec(const QList<QStringList> &args,
+ QMakeProject *proj, QMap<QString, QStringList> &place,
+ QStringList &functionReturn)
+{
+ //save state
+#if 1
+ calling_place = &place;
+#else
+ calling_place = &proj->variables();
+#endif
+ return_value.clear();
+ cause_return = false;
+
+ //execute
+#if 0
+ vars = proj->variables(); // should be place so that local variables can be inherited
+#else
+ vars = place;
+#endif
+ vars["ARGS"].clear();
+ for(int i = 0; i < args.count(); i++) {
+ vars["ARGS"] += args[i];
+ vars[QString::number(i+1)] = args[i];
+ }
+ bool ret = ParsableBlock::eval(proj, vars);
+ functionReturn = return_value;
+
+ //restore state
+ calling_place = 0;
+ return_value.clear();
+ vars.clear();
+ return ret;
+}
+
+//loops
+struct IteratorBlock : public ParsableBlock
+{
+ IteratorBlock() : scope_level(1), loop_forever(false), cause_break(false), cause_next(false) { }
+
+ int scope_level;
+
+ struct Test {
+ QString func;
+ QStringList args;
+ bool invert;
+ parser_info pi;
+ Test(const QString &f, QStringList &a, bool i) : func(f), args(a), invert(i) { pi = parser; }
+ };
+ QList<Test> test;
+
+ QString variable;
+
+ bool loop_forever, cause_break, cause_next;
+ QStringList list;
+
+ bool exec(QMakeProject *p, QMap<QString, QStringList> &place);
+ virtual bool continueBlock() { return !cause_next && !cause_break; }
+};
+bool IteratorBlock::exec(QMakeProject *p, QMap<QString, QStringList> &place)
+{
+ bool ret = true;
+ QStringList::Iterator it;
+ if(!loop_forever)
+ it = list.begin();
+ int iterate_count = 0;
+ //save state
+ IteratorBlock *saved_iterator = p->iterator;
+ p->iterator = this;
+
+ //do the loop
+ while(loop_forever || it != list.end()) {
+ cause_next = cause_break = false;
+ if(!loop_forever && (*it).isEmpty()) { //ignore empty items
+ ++it;
+ continue;
+ }
+
+ //set up the loop variable
+ QStringList va;
+ if(!variable.isEmpty()) {
+ va = place[variable];
+ if(loop_forever)
+ place[variable] = QStringList(QString::number(iterate_count));
+ else
+ place[variable] = QStringList(*it);
+ }
+ //do the iterations
+ bool succeed = true;
+ for(QList<Test>::Iterator test_it = test.begin(); test_it != test.end(); ++test_it) {
+ parser = (*test_it).pi;
+ succeed = p->doProjectTest((*test_it).func, (*test_it).args, place);
+ if((*test_it).invert)
+ succeed = !succeed;
+ if(!succeed)
+ break;
+ }
+ if(succeed)
+ ret = ParsableBlock::eval(p, place);
+ //restore the variable in the map
+ if(!variable.isEmpty())
+ place[variable] = va;
+ //loop counters
+ if(!loop_forever)
+ ++it;
+ iterate_count++;
+ if(!ret || cause_break)
+ break;
+ }
+
+ //restore state
+ p->iterator = saved_iterator;
+ return ret;
+}
+
+QMakeProject::ScopeBlock::~ScopeBlock()
+{
+#if 0
+ if(iterate)
+ delete iterate;
+#endif
+}
+
+static void qmake_error_msg(const QString &msg)
+{
+ fprintf(stderr, "%s:%d: %s\n", parser.file.toLatin1().constData(), parser.line_no,
+ msg.toLatin1().constData());
+}
+
+/*
+ 1) environment variable QMAKEFEATURES (as separated by colons)
+ 2) property variable QMAKEFEATURES (as separated by colons)
+ 3) <project_root> (where .qmake.cache lives) + FEATURES_DIR
+ 4) environment variable QMAKEPATH (as separated by colons) + /mkspecs/FEATURES_DIR
+ 5) your QMAKESPEC/features dir
+ 6) your data_install/mkspecs/FEATURES_DIR
+ 7) your QMAKESPEC/../FEATURES_DIR dir
+
+ FEATURES_DIR is defined as:
+
+ 1) features/(unix|win32|macx)/
+ 2) features/
+*/
+QStringList qmake_feature_paths(QMakeProperty *prop=0)
+{
+ QStringList concat;
+ {
+ const QString base_concat = QDir::separator() + QString("features");
+ switch(Option::target_mode) {
+ case Option::TARG_MACX_MODE: //also a unix
+ concat << base_concat + QDir::separator() + "mac";
+ concat << base_concat + QDir::separator() + "macx";
+ concat << base_concat + QDir::separator() + "unix";
+ break;
+ default: // Can't happen, just make the compiler shut up
+ case Option::TARG_UNIX_MODE:
+ concat << base_concat + QDir::separator() + "unix";
+ break;
+ case Option::TARG_WIN_MODE:
+ concat << base_concat + QDir::separator() + "win32";
+ break;
+ case Option::TARG_SYMBIAN_MODE:
+ concat << base_concat + QDir::separator() + "symbian";
+ break;
+ }
+ concat << base_concat;
+ }
+ const QString mkspecs_concat = QDir::separator() + QString("mkspecs");
+ QStringList feature_roots;
+ QByteArray mkspec_path = qgetenv("QMAKEFEATURES");
+ if(!mkspec_path.isNull())
+ feature_roots += splitPathList(QString::fromLocal8Bit(mkspec_path));
+ if(prop)
+ feature_roots += splitPathList(prop->value("QMAKEFEATURES"));
+ if(!Option::mkfile::cachefile.isEmpty()) {
+ QString path;
+ int last_slash = Option::mkfile::cachefile.lastIndexOf(QDir::separator());
+ if(last_slash != -1)
+ path = Option::fixPathToLocalOS(Option::mkfile::cachefile.left(last_slash), false);
+ for(QStringList::Iterator concat_it = concat.begin();
+ concat_it != concat.end(); ++concat_it)
+ feature_roots << (path + (*concat_it));
+ }
+ QByteArray qmakepath = qgetenv("QMAKEPATH");
+ if (!qmakepath.isNull()) {
+ const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath));
+ for(QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) {
+ for(QStringList::Iterator concat_it = concat.begin();
+ concat_it != concat.end(); ++concat_it)
+ feature_roots << ((*it) + mkspecs_concat + (*concat_it));
+ }
+ }
+ if(!Option::mkfile::qmakespec.isEmpty())
+ feature_roots << Option::mkfile::qmakespec + QDir::separator() + "features";
+ if(!Option::mkfile::qmakespec.isEmpty()) {
+ QFileInfo specfi(Option::mkfile::qmakespec);
+ QDir specdir(specfi.absoluteFilePath());
+ while(!specdir.isRoot()) {
+ if(!specdir.cdUp() || specdir.isRoot())
+ break;
+ if(QFile::exists(specdir.path() + QDir::separator() + "features")) {
+ for(QStringList::Iterator concat_it = concat.begin();
+ concat_it != concat.end(); ++concat_it)
+ feature_roots << (specdir.path() + (*concat_it));
+ break;
+ }
+ }
+ }
+ for(QStringList::Iterator concat_it = concat.begin();
+ concat_it != concat.end(); ++concat_it)
+ feature_roots << (QLibraryInfo::location(QLibraryInfo::PrefixPath) +
+ mkspecs_concat + (*concat_it));
+ for(QStringList::Iterator concat_it = concat.begin();
+ concat_it != concat.end(); ++concat_it)
+ feature_roots << (QLibraryInfo::location(QLibraryInfo::DataPath) +
+ mkspecs_concat + (*concat_it));
+ return feature_roots;
+}
+
+QStringList qmake_mkspec_paths()
+{
+ QStringList ret;
+ const QString concat = QDir::separator() + QString("mkspecs");
+ QByteArray qmakepath = qgetenv("QMAKEPATH");
+ if (!qmakepath.isEmpty()) {
+ const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath));
+ for(QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it)
+ ret << ((*it) + concat);
+ }
+ ret << QLibraryInfo::location(QLibraryInfo::DataPath) + concat;
+
+ return ret;
+}
+
+QMakeProject::~QMakeProject()
+{
+ if(own_prop)
+ delete prop;
+ for(QMap<QString, FunctionBlock*>::iterator it = replaceFunctions.begin(); it != replaceFunctions.end(); ++it) {
+ if(!it.value()->deref())
+ delete it.value();
+ }
+ replaceFunctions.clear();
+ for(QMap<QString, FunctionBlock*>::iterator it = testFunctions.begin(); it != testFunctions.end(); ++it) {
+ if(!it.value()->deref())
+ delete it.value();
+ }
+ testFunctions.clear();
+}
+
+
+void
+QMakeProject::init(QMakeProperty *p, const QMap<QString, QStringList> *vars)
+{
+ if(vars)
+ base_vars = *vars;
+ if(!p) {
+ prop = new QMakeProperty;
+ own_prop = true;
+ } else {
+ prop = p;
+ own_prop = false;
+ }
+ recursive = false;
+ reset();
+}
+
+QMakeProject::QMakeProject(QMakeProject *p, const QMap<QString, QStringList> *vars)
+{
+ init(p->properties(), vars ? vars : &p->variables());
+ for(QMap<QString, FunctionBlock*>::iterator it = p->replaceFunctions.begin(); it != p->replaceFunctions.end(); ++it) {
+ it.value()->ref();
+ replaceFunctions.insert(it.key(), it.value());
+ }
+ for(QMap<QString, FunctionBlock*>::iterator it = p->testFunctions.begin(); it != p->testFunctions.end(); ++it) {
+ it.value()->ref();
+ testFunctions.insert(it.key(), it.value());
+ }
+}
+
+void
+QMakeProject::reset()
+{
+ // scope_blocks starts with one non-ignoring entity
+ scope_blocks.clear();
+ scope_blocks.push(ScopeBlock());
+ iterator = 0;
+ function = 0;
+ backslashWarned = false;
+}
+
+bool
+QMakeProject::parse(const QString &t, QMap<QString, QStringList> &place, int numLines)
+{
+ // To preserve the integrity of any UTF-8 characters in .pro file, temporarily replace the
+ // non-breaking space (0xA0) characters with another non-space character, so that
+ // QString::simplified() call will not replace it with space.
+ // Note: There won't be any two byte characters in .pro files, so 0x10A0 should be a safe
+ // replacement character.
+ static QChar nbsp(0xA0);
+ static QChar nbspFix(0x01A0);
+ QString s;
+ if (t.indexOf(nbsp) != -1) {
+ s = t;
+ s.replace(nbsp, nbspFix);
+ s = s.simplified();
+ s.replace(nbspFix, nbsp);
+ } else {
+ s = t.simplified();
+ }
+
+ int hash_mark = s.indexOf("#");
+ if(hash_mark != -1) //good bye comments
+ s = s.left(hash_mark);
+ if(s.isEmpty()) // blank_line
+ return true;
+
+ if(scope_blocks.top().ignore) {
+ bool continue_parsing = false;
+ // adjust scope for each block which appears on a single line
+ for(int i = 0; i < s.length(); i++) {
+ if(s[i] == '{') {
+ scope_blocks.push(ScopeBlock(true));
+ } else if(s[i] == '}') {
+ if(scope_blocks.count() == 1) {
+ fprintf(stderr, "Braces mismatch %s:%d\n", parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+ ScopeBlock sb = scope_blocks.pop();
+ if(sb.iterate) {
+ sb.iterate->exec(this, place);
+ delete sb.iterate;
+ sb.iterate = 0;
+ }
+ if(!scope_blocks.top().ignore) {
+ debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.toLatin1().constData(),
+ parser.line_no, scope_blocks.count()+1);
+ s = s.mid(i+1).trimmed();
+ continue_parsing = !s.isEmpty();
+ break;
+ }
+ }
+ }
+ if(!continue_parsing) {
+ debug_msg(1, "Project Parser: %s:%d : Ignored due to block being false.",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return true;
+ }
+ }
+
+ if(function) {
+ QString append;
+ int d_off = 0;
+ const QChar *d = s.unicode();
+ bool function_finished = false;
+ while(d_off < s.length()) {
+ if(*(d+d_off) == QLatin1Char('}')) {
+ function->scope_level--;
+ if(!function->scope_level) {
+ function_finished = true;
+ break;
+ }
+ } else if(*(d+d_off) == QLatin1Char('{')) {
+ function->scope_level++;
+ }
+ append += *(d+d_off);
+ ++d_off;
+ }
+ if(!append.isEmpty())
+ function->parselist.append(IteratorBlock::Parse(append));
+ if(function_finished) {
+ function = 0;
+ s = QString(d+d_off, s.length()-d_off);
+ } else {
+ return true;
+ }
+ } else if(IteratorBlock *it = scope_blocks.top().iterate) {
+ QString append;
+ int d_off = 0;
+ const QChar *d = s.unicode();
+ bool iterate_finished = false;
+ while(d_off < s.length()) {
+ if(*(d+d_off) == QLatin1Char('}')) {
+ it->scope_level--;
+ if(!it->scope_level) {
+ iterate_finished = true;
+ break;
+ }
+ } else if(*(d+d_off) == QLatin1Char('{')) {
+ it->scope_level++;
+ }
+ append += *(d+d_off);
+ ++d_off;
+ }
+ if(!append.isEmpty())
+ scope_blocks.top().iterate->parselist.append(IteratorBlock::Parse(append));
+ if(iterate_finished) {
+ scope_blocks.top().iterate = 0;
+ bool ret = it->exec(this, place);
+ delete it;
+ if(!ret)
+ return false;
+ s = s.mid(d_off);
+ } else {
+ return true;
+ }
+ }
+
+ QString scope, var, op;
+ QStringList val;
+#define SKIP_WS(d, o, l) while(o < l && (*(d+o) == QLatin1Char(' ') || *(d+o) == QLatin1Char('\t'))) ++o
+ const QChar *d = s.unicode();
+ int d_off = 0;
+ SKIP_WS(d, d_off, s.length());
+ IteratorBlock *iterator = 0;
+ bool scope_failed = false, else_line = false, or_op=false;
+ QChar quote = 0;
+ int parens = 0, scope_count=0, start_block = 0;
+ while(d_off < s.length()) {
+ if(!parens) {
+ if(*(d+d_off) == QLatin1Char('='))
+ break;
+ if(*(d+d_off) == QLatin1Char('+') || *(d+d_off) == QLatin1Char('-') ||
+ *(d+d_off) == QLatin1Char('*') || *(d+d_off) == QLatin1Char('~')) {
+ if(*(d+d_off+1) == QLatin1Char('=')) {
+ break;
+ } else if(*(d+d_off+1) == QLatin1Char(' ')) {
+ const QChar *k = d+d_off+1;
+ int k_off = 0;
+ SKIP_WS(k, k_off, s.length()-d_off);
+ if(*(k+k_off) == QLatin1Char('=')) {
+ QString msg;
+ qmake_error_msg(QString(d+d_off, 1) + "must be followed immediately by =");
+ return false;
+ }
+ }
+ }
+ }
+
+ if(!quote.isNull()) {
+ if(*(d+d_off) == quote)
+ quote = QChar();
+ } else if(*(d+d_off) == '(') {
+ ++parens;
+ } else if(*(d+d_off) == ')') {
+ --parens;
+ } else if(*(d+d_off) == '"' /*|| *(d+d_off) == '\''*/) {
+ quote = *(d+d_off);
+ }
+
+ if(!parens && quote.isNull() &&
+ (*(d+d_off) == QLatin1Char(':') || *(d+d_off) == QLatin1Char('{') ||
+ *(d+d_off) == QLatin1Char(')') || *(d+d_off) == QLatin1Char('|'))) {
+ scope_count++;
+ scope = var.trimmed();
+ if(*(d+d_off) == QLatin1Char(')'))
+ scope += *(d+d_off); // need this
+ var = "";
+
+ bool test = scope_failed;
+ if(scope.isEmpty()) {
+ test = true;
+ } else if(scope.toLower() == "else") { //else is a builtin scope here as it modifies state
+ if(scope_count != 1 || scope_blocks.top().else_status == ScopeBlock::TestNone) {
+ qmake_error_msg(("Unexpected " + scope + " ('" + s + "')").toLatin1());
+ return false;
+ }
+ else_line = true;
+ test = (scope_blocks.top().else_status == ScopeBlock::TestSeek);
+ debug_msg(1, "Project Parser: %s:%d : Else%s %s.", parser.file.toLatin1().constData(), parser.line_no,
+ scope == "else" ? "" : QString(" (" + scope + ")").toLatin1().constData(),
+ test ? "considered" : "excluded");
+ } else {
+ QString comp_scope = scope;
+ bool invert_test = (comp_scope.at(0) == QLatin1Char('!'));
+ if(invert_test)
+ comp_scope = comp_scope.mid(1);
+ int lparen = comp_scope.indexOf('(');
+ if(or_op == scope_failed) {
+ if(lparen != -1) { // if there is an lparen in the scope, it IS a function
+ int rparen = comp_scope.lastIndexOf(')');
+ if(rparen == -1) {
+ qmake_error_msg("Function missing right paren: " + comp_scope);
+ return false;
+ }
+ QString func = comp_scope.left(lparen);
+ QStringList args = split_arg_list(comp_scope.mid(lparen+1, rparen - lparen - 1));
+ if(function) {
+ fprintf(stderr, "%s:%d: No tests can come after a function definition!\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ } else if(func == "for") { //for is a builtin function here, as it modifies state
+ if(args.count() > 2 || args.count() < 1) {
+ fprintf(stderr, "%s:%d: for(iterate, list) requires two arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ } else if(iterator) {
+ fprintf(stderr, "%s:%d unexpected nested for()\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+
+ iterator = new IteratorBlock;
+ QString it_list;
+ if(args.count() == 1) {
+ doVariableReplace(args[0], place);
+ it_list = args[0];
+ if(args[0] != "ever") {
+ delete iterator;
+ iterator = 0;
+ fprintf(stderr, "%s:%d: for(iterate, list) requires two arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+ it_list = "forever";
+ } else if(args.count() == 2) {
+ iterator->variable = args[0];
+ doVariableReplace(args[1], place);
+ it_list = args[1];
+ }
+ QStringList list = place[it_list];
+ if(list.isEmpty()) {
+ if(it_list == "forever") {
+ iterator->loop_forever = true;
+ } else {
+ int dotdot = it_list.indexOf("..");
+ if(dotdot != -1) {
+ bool ok;
+ int start = it_list.left(dotdot).toInt(&ok);
+ if(ok) {
+ int end = it_list.mid(dotdot+2).toInt(&ok);
+ if(ok) {
+ if(start < end) {
+ for(int i = start; i <= end; i++)
+ list << QString::number(i);
+ } else {
+ for(int i = start; i >= end; i--)
+ list << QString::number(i);
+ }
+ }
+ }
+ }
+ }
+ }
+ iterator->list = list;
+ test = !invert_test;
+ } else if(iterator) {
+ iterator->test.append(IteratorBlock::Test(func, args, invert_test));
+ test = !invert_test;
+ } else if(func == "defineTest" || func == "defineReplace") {
+ if(!function_blocks.isEmpty()) {
+ fprintf(stderr,
+ "%s:%d: cannot define a function within another definition.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d: %s(function_name) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no, func.toLatin1().constData());
+ return false;
+ }
+ QMap<QString, FunctionBlock*> *map = 0;
+ if(func == "defineTest")
+ map = &testFunctions;
+ else
+ map = &replaceFunctions;
+#if 0
+ if(!map || map->contains(args[0])) {
+ fprintf(stderr, "%s:%d: Function[%s] multiply defined.\n",
+ parser.file.toLatin1().constData(), parser.line_no, args[0].toLatin1().constData());
+ return false;
+ }
+#endif
+ function = new FunctionBlock;
+ map->insert(args[0], function);
+ test = true;
+ } else {
+ test = doProjectTest(func, args, place);
+ if(*(d+d_off) == QLatin1Char(')') && d_off == s.length()-1) {
+ if(invert_test)
+ test = !test;
+ scope_blocks.top().else_status =
+ (test ? ScopeBlock::TestFound : ScopeBlock::TestSeek);
+ return true; // assume we are done
+ }
+ }
+ } else {
+ QString cscope = comp_scope.trimmed();
+ doVariableReplace(cscope, place);
+ test = isActiveConfig(cscope.trimmed(), true, &place);
+ }
+ if(invert_test)
+ test = !test;
+ }
+ }
+ if(!test && !scope_failed)
+ debug_msg(1, "Project Parser: %s:%d : Test (%s) failed.", parser.file.toLatin1().constData(),
+ parser.line_no, scope.toLatin1().constData());
+ if(test == or_op)
+ scope_failed = !test;
+ or_op = (*(d+d_off) == QLatin1Char('|'));
+
+ if(*(d+d_off) == QLatin1Char('{')) { // scoping block
+ start_block++;
+ if(iterator) {
+ for(int off = 0, braces = 0; true; ++off) {
+ if(*(d+d_off+off) == QLatin1Char('{'))
+ ++braces;
+ else if(*(d+d_off+off) == QLatin1Char('}') && braces)
+ --braces;
+ if(!braces || d_off+off == s.length()) {
+ iterator->parselist.append(s.mid(d_off, off-1));
+ if(braces > 1)
+ iterator->scope_level += braces-1;
+ d_off += off-1;
+ break;
+ }
+ }
+ }
+ }
+ } else if(!parens && *(d+d_off) == QLatin1Char('}')) {
+ if(start_block) {
+ --start_block;
+ } else if(!scope_blocks.count()) {
+ warn_msg(WarnParser, "Possible braces mismatch %s:%d", parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ if(scope_blocks.count() == 1) {
+ fprintf(stderr, "Braces mismatch %s:%d\n", parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+ debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.toLatin1().constData(),
+ parser.line_no, scope_blocks.count());
+ ScopeBlock sb = scope_blocks.pop();
+ if(sb.iterate)
+ sb.iterate->exec(this, place);
+ }
+ } else {
+ var += *(d+d_off);
+ }
+ ++d_off;
+ }
+ var = var.trimmed();
+
+ if(!else_line || (else_line && !scope_failed))
+ scope_blocks.top().else_status = (!scope_failed ? ScopeBlock::TestFound : ScopeBlock::TestSeek);
+ if(start_block) {
+ ScopeBlock next_block(scope_failed);
+ next_block.iterate = iterator;
+ if(iterator)
+ next_block.else_status = ScopeBlock::TestNone;
+ else if(scope_failed)
+ next_block.else_status = ScopeBlock::TestSeek;
+ else
+ next_block.else_status = ScopeBlock::TestFound;
+ scope_blocks.push(next_block);
+ debug_msg(1, "Project Parser: %s:%d : Entering block %d (%d). [%s]", parser.file.toLatin1().constData(),
+ parser.line_no, scope_blocks.count(), scope_failed, s.toLatin1().constData());
+ } else if(iterator) {
+ iterator->parselist.append(var+s.mid(d_off));
+ bool ret = iterator->exec(this, place);
+ delete iterator;
+ return ret;
+ }
+
+ if((!scope_count && !var.isEmpty()) || (scope_count == 1 && else_line))
+ scope_blocks.top().else_status = ScopeBlock::TestNone;
+ if(d_off == s.length()) {
+ if(!var.trimmed().isEmpty())
+ qmake_error_msg(("Parse Error ('" + s + "')").toLatin1());
+ return var.isEmpty(); // allow just a scope
+ }
+
+ SKIP_WS(d, d_off, s.length());
+ for(; d_off < s.length() && op.indexOf('=') == -1; op += *(d+(d_off++)))
+ ;
+ op.replace(QRegExp("\\s"), "");
+
+ SKIP_WS(d, d_off, s.length());
+ QString vals = s.mid(d_off); // vals now contains the space separated list of values
+ int rbraces = vals.count('}'), lbraces = vals.count('{');
+ if(scope_blocks.count() > 1 && rbraces - lbraces == 1 && vals.endsWith('}')) {
+ debug_msg(1, "Project Parser: %s:%d : Leaving block %d", parser.file.toLatin1().constData(),
+ parser.line_no, scope_blocks.count());
+ ScopeBlock sb = scope_blocks.pop();
+ if(sb.iterate)
+ sb.iterate->exec(this, place);
+ vals.truncate(vals.length()-1);
+ } else if(rbraces != lbraces) {
+ warn_msg(WarnParser, "Possible braces mismatch {%s} %s:%d",
+ vals.toLatin1().constData(), parser.file.toLatin1().constData(), parser.line_no);
+ }
+ if(scope_failed)
+ return true; // oh well
+#undef SKIP_WS
+
+ doVariableReplace(var, place);
+ var = varMap(var); //backwards compatibility
+ if(!var.isEmpty() && Option::mkfile::do_preprocess) {
+ static QString last_file("*none*");
+ if(parser.file != last_file) {
+ fprintf(stdout, "#file %s:%d\n", parser.file.toLatin1().constData(), parser.line_no);
+ last_file = parser.file;
+ }
+ fprintf(stdout, "%s %s %s\n", var.toLatin1().constData(), op.toLatin1().constData(), vals.toLatin1().constData());
+ }
+
+ if(vals.contains('=') && numLines > 1)
+ warn_msg(WarnParser, "Possible accidental line continuation: {%s} at %s:%d",
+ var.toLatin1().constData(), parser.file.toLatin1().constData(), parser.line_no);
+
+ QStringList &varlist = place[var]; // varlist is the list in the symbol table
+
+ if(Option::debug_level >= 1) {
+ QString tmp_vals = vals;
+ doVariableReplace(tmp_vals, place);
+ debug_msg(1, "Project Parser: %s:%d :%s: :%s: (%s)", parser.file.toLatin1().constData(), parser.line_no,
+ var.toLatin1().constData(), op.toLatin1().constData(), tmp_vals.toLatin1().constData());
+ }
+
+ // now do the operation
+ if(op == "~=") {
+ doVariableReplace(vals, place);
+ if(vals.length() < 4 || vals.at(0) != 's') {
+ qmake_error_msg(("~= operator only can handle s/// function ('" +
+ s + "')").toLatin1());
+ return false;
+ }
+ QChar sep = vals.at(1);
+ QStringList func = vals.split(sep);
+ if(func.count() < 3 || func.count() > 4) {
+ qmake_error_msg(("~= operator only can handle s/// function ('" +
+ s + "')").toLatin1());
+ return false;
+ }
+ bool global = false, case_sense = true, quote = false;
+ if(func.count() == 4) {
+ global = func[3].indexOf('g') != -1;
+ case_sense = func[3].indexOf('i') == -1;
+ quote = func[3].indexOf('q') != -1;
+ }
+ QString from = func[1], to = func[2];
+ if(quote)
+ from = QRegExp::escape(from);
+ QRegExp regexp(from, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive);
+ for(QStringList::Iterator varit = varlist.begin(); varit != varlist.end();) {
+ if((*varit).contains(regexp)) {
+ (*varit) = (*varit).replace(regexp, to);
+ if ((*varit).isEmpty())
+ varit = varlist.erase(varit);
+ else
+ ++varit;
+ if(!global)
+ break;
+ } else
+ ++varit;
+ }
+ } else {
+ QStringList vallist;
+ {
+ //doVariableReplace(vals, place);
+ QStringList tmp = split_value_list(vals);
+ for(int i = 0; i < tmp.size(); ++i)
+ vallist += doVariableReplaceExpand(tmp[i], place);
+ }
+
+ if(op == "=") {
+ if(!varlist.isEmpty()) {
+ bool send_warning = false;
+ if(var != "TEMPLATE" && var != "TARGET") {
+ QSet<QString> incoming_vals = vallist.toSet();
+ for(int i = 0; i < varlist.size(); ++i) {
+ const QString var = varlist.at(i).trimmed();
+ if(!var.isEmpty() && !incoming_vals.contains(var)) {
+ send_warning = true;
+ break;
+ }
+ }
+ }
+ if(send_warning)
+ warn_msg(WarnParser, "Operator=(%s) clears variables previously set: %s:%d",
+ var.toLatin1().constData(), parser.file.toLatin1().constData(), parser.line_no);
+ }
+ varlist.clear();
+ }
+ for(QStringList::ConstIterator valit = vallist.begin();
+ valit != vallist.end(); ++valit) {
+ if((*valit).isEmpty())
+ continue;
+ if((op == "*=" && !varlist.contains((*valit))) ||
+ op == "=" || op == "+=")
+ varlist.append((*valit));
+ else if(op == "-=")
+ varlist.removeAll((*valit));
+ }
+ if(var == "REQUIRES") // special case to get communicated to backends!
+ doProjectCheckReqs(vallist, place);
+ }
+ return true;
+}
+
+bool
+QMakeProject::read(QTextStream &file, QMap<QString, QStringList> &place)
+{
+ int numLines = 0;
+ bool ret = true;
+ QString s;
+ while(!file.atEnd()) {
+ parser.line_no++;
+ QString line = file.readLine().trimmed();
+ int prelen = line.length();
+
+ int hash_mark = line.indexOf("#");
+ if(hash_mark != -1) //good bye comments
+ line = line.left(hash_mark).trimmed();
+ if(!line.isEmpty() && line.right(1) == "\\") {
+ if(!line.startsWith("#")) {
+ line.truncate(line.length() - 1);
+ s += line + Option::field_sep;
+ ++numLines;
+ }
+ } else if(!line.isEmpty() || (line.isEmpty() && !prelen)) {
+ if(s.isEmpty() && line.isEmpty())
+ continue;
+ if(!line.isEmpty()) {
+ s += line;
+ ++numLines;
+ }
+ if(!s.isEmpty()) {
+ if(!(ret = parse(s, place, numLines))) {
+ s = "";
+ numLines = 0;
+ break;
+ }
+ s = "";
+ numLines = 0;
+ }
+ }
+ }
+ if (!s.isEmpty())
+ ret = parse(s, place, numLines);
+ return ret;
+}
+
+bool
+QMakeProject::read(const QString &file, QMap<QString, QStringList> &place)
+{
+ parser_info pi = parser;
+ reset();
+
+ const QString oldpwd = qmake_getpwd();
+ QString filename = Option::fixPathToLocalOS(file, false);
+ bool ret = false, using_stdin = false;
+ QFile qfile;
+ if(!strcmp(filename.toLatin1(), "-")) {
+ qfile.setFileName("");
+ ret = qfile.open(stdin, QIODevice::ReadOnly);
+ using_stdin = true;
+ } else if(QFileInfo(file).isDir()) {
+ return false;
+ } else {
+ qfile.setFileName(filename);
+ ret = qfile.open(QIODevice::ReadOnly);
+ qmake_setpwd(QFileInfo(filename).absolutePath());
+ }
+ if(ret) {
+ parser_info pi = parser;
+ parser.from_file = true;
+ parser.file = filename;
+ parser.line_no = 0;
+ QTextStream t(&qfile);
+ ret = read(t, place);
+ if(!using_stdin)
+ qfile.close();
+ }
+ if(scope_blocks.count() != 1) {
+ qmake_error_msg("Unterminated conditional block at end of file");
+ ret = false;
+ }
+ parser = pi;
+ qmake_setpwd(oldpwd);
+ return ret;
+}
+
+bool
+QMakeProject::read(const QString &project, uchar cmd)
+{
+ pfile = QFileInfo(project).absoluteFilePath();
+ return read(cmd);
+}
+
+bool
+QMakeProject::read(uchar cmd)
+{
+ if(cfile.isEmpty()) {
+ // hack to get the Option stuff in there
+ base_vars["QMAKE_EXT_CPP"] = Option::cpp_ext;
+ base_vars["QMAKE_EXT_C"] = Option::c_ext;
+ base_vars["QMAKE_EXT_H"] = Option::h_ext;
+ base_vars["QMAKE_SH"] = Option::shellPath;
+ if(!Option::user_template_prefix.isEmpty())
+ base_vars["TEMPLATE_PREFIX"] = QStringList(Option::user_template_prefix);
+
+ if(cmd & ReadCache && Option::mkfile::do_cache) { // parse the cache
+ int cache_depth = -1;
+ QString qmake_cache = Option::mkfile::cachefile;
+ if(qmake_cache.isEmpty()) { //find it as it has not been specified
+ QString dir = QDir::toNativeSeparators(Option::output_dir);
+ while(!QFile::exists((qmake_cache = dir + QDir::separator() + ".qmake.cache"))) {
+ dir = dir.left(dir.lastIndexOf(QDir::separator()));
+ if(dir.isEmpty() || dir.indexOf(QDir::separator()) == -1) {
+ qmake_cache = "";
+ break;
+ }
+ if(cache_depth == -1)
+ cache_depth = 1;
+ else
+ cache_depth++;
+ }
+ } else {
+ QString abs_cache = QFileInfo(Option::mkfile::cachefile).absoluteDir().path();
+ if(Option::output_dir.startsWith(abs_cache))
+ cache_depth = Option::output_dir.mid(abs_cache.length()).count('/');
+ }
+ if(!qmake_cache.isEmpty()) {
+ if(read(qmake_cache, cache)) {
+ Option::mkfile::cachefile_depth = cache_depth;
+ Option::mkfile::cachefile = qmake_cache;
+ if(Option::mkfile::qmakespec.isEmpty() && !cache["QMAKESPEC"].isEmpty())
+ Option::mkfile::qmakespec = cache["QMAKESPEC"].first();
+ }
+ }
+ }
+ if(cmd & ReadConf) { // parse mkspec
+ QString qmakespec = fixEnvVariables(Option::mkfile::qmakespec);
+ QStringList mkspec_roots = qmake_mkspec_paths();
+ debug_msg(2, "Looking for mkspec %s in (%s)", qmakespec.toLatin1().constData(),
+ mkspec_roots.join("::").toLatin1().constData());
+ if(qmakespec.isEmpty()) {
+ for(QStringList::ConstIterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
+ QString mkspec = (*it) + QDir::separator() + "default";
+ QFileInfo default_info(mkspec);
+ if(default_info.exists() && default_info.isDir()) {
+ qmakespec = mkspec;
+ break;
+ }
+ }
+ if(qmakespec.isEmpty()) {
+ fprintf(stderr, "QMAKESPEC has not been set, so configuration cannot be deduced.\n");
+ return false;
+ }
+ Option::mkfile::qmakespec = qmakespec;
+ }
+
+ if(QDir::isRelativePath(qmakespec)) {
+ if (QFile::exists(Option::output_dir+"/"+qmakespec+"/qmake.conf")) {
+ qmakespec = Option::mkfile::qmakespec = QFileInfo(Option::output_dir+"/"+qmakespec).absoluteFilePath();
+ } else if (QFile::exists(qmakespec+"/qmake.conf")) {
+ Option::mkfile::qmakespec = QFileInfo(Option::mkfile::qmakespec).absoluteFilePath();
+ } else {
+ bool found_mkspec = false;
+ for(QStringList::ConstIterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) {
+ QString mkspec = (*it) + QDir::separator() + qmakespec;
+ if(QFile::exists(mkspec)) {
+ found_mkspec = true;
+ Option::mkfile::qmakespec = qmakespec = mkspec;
+ break;
+ }
+ }
+ if(!found_mkspec) {
+ fprintf(stderr, "Could not find mkspecs for your QMAKESPEC(%s) after trying:\n\t%s\n",
+ qmakespec.toLatin1().constData(), mkspec_roots.join("\n\t").toLatin1().constData());
+ return false;
+ }
+ }
+ }
+
+ // parse qmake configuration
+ while(qmakespec.endsWith(QString(QChar(QDir::separator()))))
+ qmakespec.truncate(qmakespec.length()-1);
+ QString spec = qmakespec + QDir::separator() + "qmake.conf";
+ debug_msg(1, "QMAKESPEC conf: reading %s", spec.toLatin1().constData());
+ if(!read(spec, base_vars)) {
+ fprintf(stderr, "Failure to read QMAKESPEC conf file %s.\n", spec.toLatin1().constData());
+ return false;
+ }
+ validateModes();
+
+ if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty()) {
+ debug_msg(1, "QMAKECACHE file: reading %s", Option::mkfile::cachefile.toLatin1().constData());
+ read(Option::mkfile::cachefile, base_vars);
+ }
+ }
+
+ if(cmd & ReadFeatures) {
+ debug_msg(1, "Processing default_pre: %s", vars["CONFIG"].join("::").toLatin1().constData());
+ if(doProjectInclude("default_pre", IncludeFlagFeature, base_vars) == IncludeNoExist)
+ doProjectInclude("default", IncludeFlagFeature, base_vars);
+ }
+ }
+
+ vars = base_vars; // start with the base
+
+ //get a default
+ if(pfile != "-" && vars["TARGET"].isEmpty())
+ vars["TARGET"].append(QFileInfo(pfile).baseName());
+
+ //before commandline
+ if(cmd & ReadCmdLine) {
+ cfile = pfile;
+ parser.file = "(internal)";
+ parser.from_file = false;
+ parser.line_no = 1; //really arg count now.. duh
+ reset();
+ for(QStringList::ConstIterator it = Option::before_user_vars.begin();
+ it != Option::before_user_vars.end(); ++it) {
+ if(!parse((*it), vars)) {
+ fprintf(stderr, "Argument failed to parse: %s\n", (*it).toLatin1().constData());
+ return false;
+ }
+ parser.line_no++;
+ }
+ }
+
+ //commandline configs
+ if(cmd & ReadConfigs && !Option::user_configs.isEmpty()) {
+ parser.file = "(configs)";
+ parser.from_file = false;
+ parser.line_no = 1; //really arg count now.. duh
+ parse("CONFIG += " + Option::user_configs.join(" "), vars);
+ }
+
+ if(cmd & ReadProFile) { // parse project file
+ debug_msg(1, "Project file: reading %s", pfile.toLatin1().constData());
+ if(pfile != "-" && !QFile::exists(pfile) && !pfile.endsWith(Option::pro_ext))
+ pfile += Option::pro_ext;
+ if(!read(pfile, vars))
+ return false;
+ }
+
+ if(cmd & ReadCmdLine) {
+ parser.file = "(internal)";
+ parser.from_file = false;
+ parser.line_no = 1; //really arg count now.. duh
+ reset();
+ for(QStringList::ConstIterator it = Option::after_user_vars.begin();
+ it != Option::after_user_vars.end(); ++it) {
+ if(!parse((*it), vars)) {
+ fprintf(stderr, "Argument failed to parse: %s\n", (*it).toLatin1().constData());
+ return false;
+ }
+ parser.line_no++;
+ }
+ }
+
+ //after configs (set in BUILDS)
+ if(cmd & ReadConfigs && !Option::after_user_configs.isEmpty()) {
+ parser.file = "(configs)";
+ parser.from_file = false;
+ parser.line_no = 1; //really arg count now.. duh
+ parse("CONFIG += " + Option::after_user_configs.join(" "), vars);
+ }
+
+ if(pfile != "-" && vars["TARGET"].isEmpty())
+ vars["TARGET"].append(QFileInfo(pfile).baseName());
+
+ if(cmd & ReadConfigs && !Option::user_configs.isEmpty()) {
+ parser.file = "(configs)";
+ parser.from_file = false;
+ parser.line_no = 1; //really arg count now.. duh
+ parse("CONFIG += " + Option::user_configs.join(" "), base_vars);
+ }
+
+ if(cmd & ReadFeatures) {
+ debug_msg(1, "Processing default_post: %s", vars["CONFIG"].join("::").toLatin1().constData());
+ doProjectInclude("default_post", IncludeFlagFeature, vars);
+
+ QHash<QString, bool> processed;
+ const QStringList &configs = vars["CONFIG"];
+ debug_msg(1, "Processing CONFIG features: %s", configs.join("::").toLatin1().constData());
+ while(1) {
+ bool finished = true;
+ for(int i = configs.size()-1; i >= 0; --i) {
+ const QString config = configs[i].toLower();
+ if(!processed.contains(config)) {
+ processed.insert(config, true);
+ if(doProjectInclude(config, IncludeFlagFeature, vars) == IncludeSuccess) {
+ finished = false;
+ break;
+ }
+ }
+ }
+ if(finished)
+ break;
+ }
+ }
+ Option::postProcessProject(this); // let Option post-process
+ return true;
+}
+
+void QMakeProject::validateModes()
+{
+ if (Option::host_mode == Option::HOST_UNKNOWN_MODE
+ || Option::target_mode == Option::TARG_UNKNOWN_MODE) {
+ Option::HOST_MODE host_mode;
+ Option::TARG_MODE target_mode;
+ const QStringList &gen = base_vars.value("MAKEFILE_GENERATOR");
+ if (gen.isEmpty()) {
+ fprintf(stderr, "%s:%d: Using OS scope before setting MAKEFILE_GENERATOR\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else if (MetaMakefileGenerator::modesForGenerator(gen.first(),
+ &host_mode, &target_mode)) {
+ if (Option::host_mode == Option::HOST_UNKNOWN_MODE) {
+ Option::host_mode = host_mode;
+ Option::applyHostMode();
+ }
+
+ if (Option::target_mode == Option::TARG_UNKNOWN_MODE) {
+ const QStringList &tgt = base_vars.value("TARGET_PLATFORM");
+ if (!tgt.isEmpty()) {
+ const QString &os = tgt.first();
+ if (os == "unix")
+ Option::target_mode = Option::TARG_UNIX_MODE;
+ else if (os == "macx")
+ Option::target_mode = Option::TARG_MACX_MODE;
+ else if (os == "symbian")
+ Option::target_mode = Option::TARG_SYMBIAN_MODE;
+ else if (os == "win32")
+ Option::target_mode = Option::TARG_WIN_MODE;
+ else
+ fprintf(stderr, "Unknown target platform specified: %s\n",
+ os.toLatin1().constData());
+ } else {
+ Option::target_mode = target_mode;
+ }
+ }
+ }
+ }
+}
+
+bool
+QMakeProject::isActiveConfig(const QString &x, bool regex, QMap<QString, QStringList> *place)
+{
+ if(x.isEmpty())
+ return true;
+
+ //magic types for easy flipping
+ if(x == "true")
+ return true;
+ else if(x == "false")
+ return false;
+
+ if (x == "unix") {
+ validateModes();
+ return Option::target_mode == Option::TARG_UNIX_MODE
+ || Option::target_mode == Option::TARG_MACX_MODE
+ || Option::target_mode == Option::TARG_SYMBIAN_MODE;
+ } else if (x == "macx" || x == "mac") {
+ validateModes();
+ return Option::target_mode == Option::TARG_MACX_MODE;
+ } else if (x == "symbian") {
+ validateModes();
+ return Option::target_mode == Option::TARG_SYMBIAN_MODE;
+ } else if (x == "win32") {
+ validateModes();
+ return Option::target_mode == Option::TARG_WIN_MODE;
+ }
+
+ //mkspecs
+ static QString spec;
+ if(spec.isEmpty())
+ spec = QFileInfo(Option::mkfile::qmakespec).fileName();
+ QRegExp re(x, Qt::CaseSensitive, QRegExp::Wildcard);
+ if((regex && re.exactMatch(spec)) || (!regex && spec == x))
+ return true;
+#ifdef Q_OS_UNIX
+ else if(spec == "default") {
+ static char *buffer = NULL;
+ if(!buffer) {
+ buffer = (char *)malloc(1024);
+ qmakeAddCacheClear(qmakeFreeCacheClear, (void**)&buffer);
+ }
+ int l = readlink(Option::mkfile::qmakespec.toLatin1(), buffer, 1024);
+ if(l != -1) {
+ buffer[l] = '\0';
+ QString r = buffer;
+ if(r.lastIndexOf('/') != -1)
+ r = r.mid(r.lastIndexOf('/') + 1);
+ if((regex && re.exactMatch(r)) || (!regex && r == x))
+ return true;
+ }
+ }
+#elif defined(Q_OS_WIN)
+ else if(spec == "default") {
+ // We can't resolve symlinks as they do on Unix, so configure.exe puts the source of the
+ // qmake.conf at the end of the default/qmake.conf in the QMAKESPEC_ORG variable.
+ const QStringList &spec_org = (place ? (*place)["QMAKESPEC_ORIGINAL"]
+ : vars["QMAKESPEC_ORIGINAL"]);
+ if (!spec_org.isEmpty()) {
+ spec = spec_org.at(0);
+ int lastSlash = spec.lastIndexOf('/');
+ if(lastSlash != -1)
+ spec = spec.mid(lastSlash + 1);
+ if((regex && re.exactMatch(spec)) || (!regex && spec == x))
+ return true;
+ }
+ }
+#endif
+
+ //simple matching
+ const QStringList &configs = (place ? (*place)["CONFIG"] : vars["CONFIG"]);
+ for(QStringList::ConstIterator it = configs.begin(); it != configs.end(); ++it) {
+ if(((regex && re.exactMatch((*it))) || (!regex && (*it) == x)) && re.exactMatch((*it)))
+ return true;
+ }
+ return false;
+}
+
+bool
+QMakeProject::doProjectTest(QString str, QMap<QString, QStringList> &place)
+{
+ QString chk = remove_quotes(str);
+ if(chk.isEmpty())
+ return true;
+ bool invert_test = (chk.left(1) == "!");
+ if(invert_test)
+ chk = chk.mid(1);
+
+ bool test=false;
+ int lparen = chk.indexOf('(');
+ if(lparen != -1) { // if there is an lparen in the chk, it IS a function
+ int rparen = chk.indexOf(')', lparen);
+ if(rparen == -1) {
+ qmake_error_msg("Function missing right paren: " + chk);
+ } else {
+ QString func = chk.left(lparen);
+ test = doProjectTest(func, chk.mid(lparen+1, rparen - lparen - 1), place);
+ }
+ } else {
+ test = isActiveConfig(chk, true, &place);
+ }
+ if(invert_test)
+ return !test;
+ return test;
+}
+
+bool
+QMakeProject::doProjectTest(QString func, const QString &params,
+ QMap<QString, QStringList> &place)
+{
+ return doProjectTest(func, split_arg_list(params), place);
+}
+
+QMakeProject::IncludeStatus
+QMakeProject::doProjectInclude(QString file, uchar flags, QMap<QString, QStringList> &place)
+{
+ enum { UnknownFormat, ProFormat, JSFormat } format = UnknownFormat;
+ if(flags & IncludeFlagFeature) {
+ if(!file.endsWith(Option::prf_ext))
+ file += Option::prf_ext;
+ validateModes(); // init dir_sep
+ if(file.indexOf(Option::dir_sep) == -1 || !QFile::exists(file)) {
+ static QStringList *feature_roots = 0;
+ if(!feature_roots) {
+ feature_roots = new QStringList(qmake_feature_paths(prop));
+ qmakeAddCacheClear(qmakeDeleteCacheClear<QStringList>, (void**)&feature_roots);
+ }
+ debug_msg(2, "Looking for feature '%s' in (%s)", file.toLatin1().constData(),
+ feature_roots->join("::").toLatin1().constData());
+ int start_root = 0;
+ if(parser.from_file) {
+ QFileInfo currFile(parser.file), prfFile(file);
+ if(currFile.fileName() == prfFile.fileName()) {
+ currFile = QFileInfo(currFile.canonicalFilePath());
+ for(int root = 0; root < feature_roots->size(); ++root) {
+ prfFile = QFileInfo(feature_roots->at(root) +
+ QDir::separator() + file).canonicalFilePath();
+ if(prfFile == currFile) {
+ start_root = root+1;
+ break;
+ }
+ }
+ }
+ }
+ for(int root = start_root; root < feature_roots->size(); ++root) {
+ QString prf(feature_roots->at(root) + QDir::separator() + file);
+ if(QFile::exists(prf + Option::js_ext)) {
+ format = JSFormat;
+ file = prf + Option::js_ext;
+ break;
+ } else if(QFile::exists(prf)) {
+ format = ProFormat;
+ file = prf;
+ break;
+ }
+ }
+ if(format == UnknownFormat)
+ return IncludeNoExist;
+ }
+ if(place["QMAKE_INTERNAL_INCLUDED_FEATURES"].indexOf(file) != -1)
+ return IncludeFeatureAlreadyLoaded;
+ place["QMAKE_INTERNAL_INCLUDED_FEATURES"].append(file);
+ }
+ if(QDir::isRelativePath(file)) {
+ QStringList include_roots;
+ if(Option::output_dir != qmake_getpwd())
+ include_roots << qmake_getpwd();
+ include_roots << Option::output_dir;
+ for(int root = 0; root < include_roots.size(); ++root) {
+ QString testName = QDir::toNativeSeparators(include_roots[root]);
+ if (!testName.endsWith(QString(QDir::separator())))
+ testName += QDir::separator();
+ testName += file;
+ if(QFile::exists(testName)) {
+ file = testName;
+ break;
+ }
+ }
+ }
+ if(format == UnknownFormat) {
+ if(QFile::exists(file)) {
+ if(file.endsWith(Option::js_ext))
+ format = JSFormat;
+ else
+ format = ProFormat;
+ } else {
+ return IncludeNoExist;
+ }
+ }
+ if(Option::mkfile::do_preprocess) //nice to see this first..
+ fprintf(stderr, "#switching file %s(%s) - %s:%d\n", (flags & IncludeFlagFeature) ? "load" : "include",
+ file.toLatin1().constData(),
+ parser.file.toLatin1().constData(), parser.line_no);
+ debug_msg(1, "Project Parser: %s'ing file %s.", (flags & IncludeFlagFeature) ? "load" : "include",
+ file.toLatin1().constData());
+
+ QString orig_file = file;
+ int di = file.lastIndexOf(QDir::separator());
+ QString oldpwd = qmake_getpwd();
+ if(di != -1) {
+ if(!qmake_setpwd(file.left(file.lastIndexOf(QDir::separator())))) {
+ fprintf(stderr, "Cannot find directory: %s\n", file.left(di).toLatin1().constData());
+ return IncludeFailure;
+ }
+ }
+ bool parsed = false;
+ parser_info pi = parser;
+ if(format == JSFormat) {
+ warn_msg(WarnParser, "%s:%d: QtScript support disabled for %s.",
+ pi.file.toLatin1().constData(), pi.line_no, orig_file.toLatin1().constData());
+ } else {
+ QStack<ScopeBlock> sc = scope_blocks;
+ IteratorBlock *it = iterator;
+ FunctionBlock *fu = function;
+ if(flags & (IncludeFlagNewProject|IncludeFlagNewParser)) {
+ // The "project's variables" are used in other places (eg. export()) so it's not
+ // possible to use "place" everywhere. Instead just set variables and grab them later
+ QMakeProject proj(this, &place);
+ if(flags & IncludeFlagNewParser) {
+#if 1
+ if(proj.doProjectInclude("default_pre", IncludeFlagFeature, proj.variables()) == IncludeNoExist)
+ proj.doProjectInclude("default", IncludeFlagFeature, proj.variables());
+#endif
+ parsed = proj.read(file, proj.variables()); // parse just that file (fromfile, infile)
+ } else {
+ parsed = proj.read(file); // parse all aux files (load/include into)
+ }
+ place = proj.variables();
+ } else {
+ parsed = read(file, place);
+ }
+ iterator = it;
+ function = fu;
+ scope_blocks = sc;
+ }
+ if(parsed) {
+ if(place["QMAKE_INTERNAL_INCLUDED_FILES"].indexOf(orig_file) == -1)
+ place["QMAKE_INTERNAL_INCLUDED_FILES"].append(orig_file);
+ } else {
+ warn_msg(WarnParser, "%s:%d: Failure to include file %s.",
+ pi.file.toLatin1().constData(), pi.line_no, orig_file.toLatin1().constData());
+ }
+ parser = pi;
+ qmake_setpwd(oldpwd);
+ if(!parsed)
+ return IncludeParseFailure;
+ return IncludeSuccess;
+}
+
+QStringList
+QMakeProject::doProjectExpand(QString func, const QString &params,
+ QMap<QString, QStringList> &place)
+{
+ return doProjectExpand(func, split_arg_list(params), place);
+}
+
+QStringList
+QMakeProject::doProjectExpand(QString func, QStringList args,
+ QMap<QString, QStringList> &place)
+{
+ QList<QStringList> args_list;
+ for(int i = 0; i < args.size(); ++i) {
+ QStringList arg = split_value_list(args[i]), tmp;
+ for(int i = 0; i < arg.size(); ++i)
+ tmp += doVariableReplaceExpand(arg[i], place);;
+ args_list += tmp;
+ }
+ return doProjectExpand(func, args_list, place);
+}
+
+// defined in symbian generator
+extern QString generate_test_uid(const QString& target);
+
+QStringList
+QMakeProject::doProjectExpand(QString func, QList<QStringList> args_list,
+ QMap<QString, QStringList> &place)
+{
+ func = func.trimmed();
+ if(replaceFunctions.contains(func)) {
+ FunctionBlock *defined = replaceFunctions[func];
+ function_blocks.push(defined);
+ QStringList ret;
+ defined->exec(args_list, this, place, ret);
+ Q_ASSERT(function_blocks.pop() == defined);
+ return ret;
+ }
+
+ QStringList args; //why don't the builtin functions just use args_list? --Sam
+ for(int i = 0; i < args_list.size(); ++i)
+ args += args_list[i].join(QString(Option::field_sep));
+
+ ExpandFunc func_t = qmake_expandFunctions().value(func);
+ if (!func_t && (func_t = qmake_expandFunctions().value(func.toLower())))
+ warn_msg(WarnDeprecated, "%s:%d: Using uppercased builtin functions is deprecated.",
+ parser.file.toLatin1().constData(), parser.line_no);
+ debug_msg(1, "Running project expand: %s(%s) [%d]",
+ func.toLatin1().constData(), args.join("::").toLatin1().constData(), func_t);
+
+ QStringList ret;
+ switch(func_t) {
+ case E_MEMBER: {
+ if(args.count() < 1 || args.count() > 3) {
+ fprintf(stderr, "%s:%d: member(var, start, end) requires three arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ bool ok = true;
+ const QStringList &var = values(args.first(), place);
+ int start = 0, end = 0;
+ if(args.count() >= 2) {
+ QString start_str = args[1];
+ start = start_str.toInt(&ok);
+ if(!ok) {
+ if(args.count() == 2) {
+ int dotdot = start_str.indexOf("..");
+ if(dotdot != -1) {
+ start = start_str.left(dotdot).toInt(&ok);
+ if(ok)
+ end = start_str.mid(dotdot+2).toInt(&ok);
+ }
+ }
+ if(!ok)
+ fprintf(stderr, "%s:%d: member() argument 2 (start) '%s' invalid.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ start_str.toLatin1().constData());
+ } else {
+ end = start;
+ if(args.count() == 3)
+ end = args[2].toInt(&ok);
+ if(!ok)
+ fprintf(stderr, "%s:%d: member() argument 3 (end) '%s' invalid.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ args[2].toLatin1().constData());
+ }
+ }
+ if(ok) {
+ if(start < 0)
+ start += var.count();
+ if(end < 0)
+ end += var.count();
+ if(start < 0 || start >= var.count() || end < 0 || end >= var.count()) {
+ //nothing
+ } else if(start < end) {
+ for(int i = start; i <= end && (int)var.count() >= i; i++)
+ ret += var[i];
+ } else {
+ for(int i = start; i >= end && (int)var.count() >= i && i >= 0; i--)
+ ret += var[i];
+ }
+ }
+ }
+ break; }
+ case E_FIRST:
+ case E_LAST: {
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d: %s(var) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no, func.toLatin1().constData());
+ } else {
+ const QStringList &var = values(args.first(), place);
+ if(!var.isEmpty()) {
+ if(func_t == E_FIRST)
+ ret = QStringList(var[0]);
+ else
+ ret = QStringList(var[var.size()-1]);
+ }
+ }
+ break; }
+ case E_CAT: {
+ if(args.count() < 1 || args.count() > 2) {
+ fprintf(stderr, "%s:%d: cat(file) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ QString file = args[0];
+ file = Option::fixPathToLocalOS(file);
+
+ bool singleLine = true;
+ if(args.count() > 1)
+ singleLine = (args[1].toLower() == "true");
+
+ QFile qfile(file);
+ if(qfile.open(QIODevice::ReadOnly)) {
+ QTextStream stream(&qfile);
+ while(!stream.atEnd()) {
+ ret += split_value_list(stream.readLine().trimmed());
+ if(!singleLine)
+ ret += "\n";
+ }
+ qfile.close();
+ }
+ }
+ break; }
+ case E_FROMFILE: {
+ if(args.count() != 2) {
+ fprintf(stderr, "%s:%d: fromfile(file, variable) requires two arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ QString file = args[0], seek_var = args[1];
+ file = Option::fixPathToLocalOS(file);
+
+ QMap<QString, QStringList> tmp;
+ if(doProjectInclude(file, IncludeFlagNewParser, tmp) == IncludeSuccess) {
+ if(tmp.contains("QMAKE_INTERNAL_INCLUDED_FILES")) {
+ QStringList &out = place["QMAKE_INTERNAL_INCLUDED_FILES"];
+ const QStringList &in = tmp["QMAKE_INTERNAL_INCLUDED_FILES"];
+ for(int i = 0; i < in.size(); ++i) {
+ if(out.indexOf(in[i]) == -1)
+ out += in[i];
+ }
+ }
+ ret = tmp[seek_var];
+ }
+ }
+ break; }
+ case E_EVAL: {
+ if(args.count() < 1 || args.count() > 2) {
+ fprintf(stderr, "%s:%d: eval(variable) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+
+ } else {
+ const QMap<QString, QStringList> *source = &place;
+ if(args.count() == 2) {
+ if(args.at(1) == "Global") {
+ source = &vars;
+ } else if(args.at(1) == "Local") {
+ source = &place;
+ } else {
+ fprintf(stderr, "%s:%d: unexpected source to eval.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ }
+ }
+ ret += source->value(args.at(0));
+ }
+ break; }
+ case E_LIST: {
+ static int x = 0;
+ QString tmp;
+ tmp.sprintf(".QMAKE_INTERNAL_TMP_VAR_%d", x++);
+ ret = QStringList(tmp);
+ QStringList &lst = (*((QMap<QString, QStringList>*)&place))[tmp];
+ lst.clear();
+ for(QStringList::ConstIterator arg_it = args.begin();
+ arg_it != args.end(); ++arg_it)
+ lst += split_value_list((*arg_it));
+ break; }
+ case E_SPRINTF: {
+ if(args.count() < 1) {
+ fprintf(stderr, "%s:%d: sprintf(format, ...) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ QString tmp = args.at(0);
+ for(int i = 1; i < args.count(); ++i)
+ tmp = tmp.arg(args.at(i));
+ ret = split_value_list(tmp);
+ }
+ break; }
+ case E_JOIN: {
+ if(args.count() < 1 || args.count() > 4) {
+ fprintf(stderr, "%s:%d: join(var, glue, before, after) requires four"
+ "arguments.\n", parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ QString glue, before, after;
+ if(args.count() >= 2)
+ glue = args[1];
+ if(args.count() >= 3)
+ before = args[2];
+ if(args.count() == 4)
+ after = args[3];
+ const QStringList &var = values(args.first(), place);
+ if(!var.isEmpty())
+ ret = split_value_list(before + var.join(glue) + after);
+ }
+ break; }
+ case E_SPLIT: {
+ if(args.count() < 1 || args.count() > 2) {
+ fprintf(stderr, "%s:%d split(var, sep) requires one or two arguments\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ QString sep = QString(Option::field_sep);
+ if(args.count() >= 2)
+ sep = args[1];
+ QStringList var = values(args.first(), place);
+ for(QStringList::ConstIterator vit = var.begin(); vit != var.end(); ++vit) {
+ QStringList lst = (*vit).split(sep);
+ for(QStringList::ConstIterator spltit = lst.begin(); spltit != lst.end(); ++spltit)
+ ret += (*spltit);
+ }
+ }
+ break; }
+ case E_BASENAME:
+ case E_DIRNAME:
+ case E_SECTION: {
+ bool regexp = false;
+ QString sep, var;
+ int beg=0, end=-1;
+ if(func_t == E_SECTION) {
+ if(args.count() != 3 && args.count() != 4) {
+ fprintf(stderr, "%s:%d section(var, sep, begin, end) requires three argument\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ var = args[0];
+ sep = args[1];
+ beg = args[2].toInt();
+ if(args.count() == 4)
+ end = args[3].toInt();
+ }
+ } else {
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d %s(var) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no, func.toLatin1().constData());
+ } else {
+ var = args[0];
+ regexp = true;
+ sep = "[" + QRegExp::escape(Option::dir_sep) + "/]";
+ if(func_t == E_DIRNAME)
+ end = -2;
+ else
+ beg = -1;
+ }
+ }
+ if(!var.isNull()) {
+ const QStringList &l = values(var, place);
+ for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
+ QString separator = sep;
+ if(regexp)
+ ret += (*it).section(QRegExp(separator), beg, end);
+ else
+ ret += (*it).section(separator, beg, end);
+ }
+ }
+ break; }
+ case E_FIND: {
+ if(args.count() != 2) {
+ fprintf(stderr, "%s:%d find(var, str) requires two arguments\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ QRegExp regx(args[1]);
+ const QStringList &var = values(args.first(), place);
+ for(QStringList::ConstIterator vit = var.begin();
+ vit != var.end(); ++vit) {
+ if(regx.indexIn(*vit) != -1)
+ ret += (*vit);
+ }
+ }
+ break; }
+ case E_SYSTEM: {
+ if(args.count() < 1 || args.count() > 2) {
+ fprintf(stderr, "%s:%d system(execut) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ char buff[256];
+ bool singleLine = true;
+ if(args.count() > 1)
+ singleLine = (args[1].toLower() == "true");
+ QString output;
+ FILE *proc = QT_POPEN(args[0].toLatin1(), "r");
+ while(proc && !feof(proc)) {
+ int read_in = int(fread(buff, 1, 255, proc));
+ if(!read_in)
+ break;
+ for(int i = 0; i < read_in; i++) {
+ if((singleLine && buff[i] == '\n') || buff[i] == '\t')
+ buff[i] = ' ';
+ }
+ buff[read_in] = '\0';
+ output += buff;
+ }
+ ret += split_value_list(output);
+ if(proc)
+ QT_PCLOSE(proc);
+ }
+ break; }
+ case E_UNIQUE: {
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d unique(var) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ const QStringList &var = values(args.first(), place);
+ for(int i = 0; i < var.count(); i++) {
+ if(!ret.contains(var[i]))
+ ret.append(var[i]);
+ }
+ }
+ break; }
+ case E_QUOTE:
+ ret = args;
+ break;
+ case E_ESCAPE_EXPAND: {
+ for(int i = 0; i < args.size(); ++i) {
+ QChar *i_data = args[i].data();
+ int i_len = args[i].length();
+ for(int x = 0; x < i_len; ++x) {
+ if(*(i_data+x) == '\\' && x < i_len-1) {
+ if(*(i_data+x+1) == '\\') {
+ ++x;
+ } else {
+ struct {
+ char in, out;
+ } mapped_quotes[] = {
+ { 'n', '\n' },
+ { 't', '\t' },
+ { 'r', '\r' },
+ { 0, 0 }
+ };
+ for(int i = 0; mapped_quotes[i].in; ++i) {
+ if(*(i_data+x+1) == mapped_quotes[i].in) {
+ *(i_data+x) = mapped_quotes[i].out;
+ if(x < i_len-2)
+ memmove(i_data+x+1, i_data+x+2, (i_len-x-2)*sizeof(QChar));
+ --i_len;
+ break;
+ }
+ }
+ }
+ }
+ }
+ ret.append(QString(i_data, i_len));
+ }
+ break; }
+ case E_RE_ESCAPE: {
+ for(int i = 0; i < args.size(); ++i)
+ ret += QRegExp::escape(args[i]);
+ break; }
+ case E_UPPER:
+ case E_LOWER: {
+ for(int i = 0; i < args.size(); ++i) {
+ if(func_t == E_UPPER)
+ ret += args[i].toUpper();
+ else
+ ret += args[i].toLower();
+ }
+ break; }
+ case E_FILES: {
+ if(args.count() != 1 && args.count() != 2) {
+ fprintf(stderr, "%s:%d files(pattern) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ bool recursive = false;
+ if(args.count() == 2)
+ recursive = (args[1].toLower() == "true" || args[1].toInt());
+ QStringList dirs;
+ QString r = Option::fixPathToLocalOS(args[0]);
+ int slash = r.lastIndexOf(QDir::separator());
+ if(slash != -1) {
+ dirs.append(r.left(slash));
+ r = r.mid(slash+1);
+ } else {
+ dirs.append("");
+ }
+
+ const QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard);
+ for(int d = 0; d < dirs.count(); d++) {
+ QString dir = dirs[d];
+ if(!dir.isEmpty() && !dir.endsWith(QDir::separator()))
+ dir += "/";
+
+ QDir qdir(dir);
+ for(int i = 0; i < (int)qdir.count(); ++i) {
+ if(qdir[i] == "." || qdir[i] == "..")
+ continue;
+ QString fname = dir + qdir[i];
+ if(QFileInfo(fname).isDir()) {
+ if(recursive)
+ dirs.append(fname);
+ }
+ if(regex.exactMatch(qdir[i]))
+ ret += fname;
+ }
+ }
+ }
+ break; }
+ case E_PROMPT: {
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d prompt(question) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else if(pfile == "-") {
+ fprintf(stderr, "%s:%d prompt(question) cannot be used when '-o -' is used.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ QString msg = fixEnvVariables(args.first());
+ if(!msg.endsWith("?"))
+ msg += "?";
+ fprintf(stderr, "Project %s: %s ", func.toUpper().toLatin1().constData(),
+ msg.toLatin1().constData());
+
+ QFile qfile;
+ if(qfile.open(stdin, QIODevice::ReadOnly)) {
+ QTextStream t(&qfile);
+ ret = split_value_list(t.readLine());
+ }
+ }
+ break; }
+ case E_REPLACE: {
+ if(args.count() != 3 ) {
+ fprintf(stderr, "%s:%d replace(var, before, after) requires three arguments\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ const QRegExp before( args[1] );
+ const QString after( args[2] );
+ QStringList var = values(args.first(), place);
+ for(QStringList::Iterator it = var.begin(); it != var.end(); ++it)
+ ret += it->replace(before, after);
+ }
+ break; }
+ case E_SIZE: {
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d: size(var) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ int size = values(args[0], place).size();
+ ret += QString::number(size);
+ }
+ break; }
+ case E_GENERATE_UID:
+ if (args.count() != 1) {
+ fprintf(stderr, "%s:%d: generate_uid(var) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ ret += generate_test_uid(args.first());
+ }
+ break;
+ default: {
+ fprintf(stderr, "%s:%d: Unknown replace function: %s\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ func.toLatin1().constData());
+ break; }
+ }
+ return ret;
+}
+
+bool
+QMakeProject::doProjectTest(QString func, QStringList args, QMap<QString, QStringList> &place)
+{
+ QList<QStringList> args_list;
+ for(int i = 0; i < args.size(); ++i) {
+ QStringList arg = split_value_list(args[i]), tmp;
+ for(int i = 0; i < arg.size(); ++i)
+ tmp += doVariableReplaceExpand(arg[i], place);
+ args_list += tmp;
+ }
+ return doProjectTest(func, args_list, place);
+}
+
+bool
+QMakeProject::doProjectTest(QString func, QList<QStringList> args_list, QMap<QString, QStringList> &place)
+{
+ func = func.trimmed();
+
+ if(testFunctions.contains(func)) {
+ FunctionBlock *defined = testFunctions[func];
+ QStringList ret;
+ function_blocks.push(defined);
+ defined->exec(args_list, this, place, ret);
+ Q_ASSERT(function_blocks.pop() == defined);
+
+ if(ret.isEmpty()) {
+ return true;
+ } else {
+ if(ret.first() == "true") {
+ return true;
+ } else if(ret.first() == "false") {
+ return false;
+ } else {
+ bool ok;
+ int val = ret.first().toInt(&ok);
+ if(ok)
+ return val;
+ fprintf(stderr, "%s:%d Unexpected return value from test %s [%s].\n",
+ parser.file.toLatin1().constData(),
+ parser.line_no, func.toLatin1().constData(),
+ ret.join("::").toLatin1().constData());
+ }
+ return false;
+ }
+ return false;
+ }
+
+ QStringList args; //why don't the builtin functions just use args_list? --Sam
+ for(int i = 0; i < args_list.size(); ++i)
+ args += args_list[i].join(QString(Option::field_sep));
+
+ TestFunc func_t = qmake_testFunctions().value(func);
+ debug_msg(1, "Running project test: %s(%s) [%d]",
+ func.toLatin1().constData(), args.join("::").toLatin1().constData(), func_t);
+
+ switch(func_t) {
+ case T_REQUIRES:
+ return doProjectCheckReqs(args, place);
+ case T_LESSTHAN:
+ case T_GREATERTHAN: {
+ if(args.count() != 2) {
+ fprintf(stderr, "%s:%d: %s(variable, value) requires two arguments.\n", parser.file.toLatin1().constData(),
+ parser.line_no, func.toLatin1().constData());
+ return false;
+ }
+ QString rhs(args[1]), lhs(values(args[0], place).join(QString(Option::field_sep)));
+ bool ok;
+ int rhs_int = rhs.toInt(&ok);
+ if(ok) { // do integer compare
+ int lhs_int = lhs.toInt(&ok);
+ if(ok) {
+ if(func_t == T_GREATERTHAN)
+ return lhs_int > rhs_int;
+ return lhs_int < rhs_int;
+ }
+ }
+ if(func_t == T_GREATERTHAN)
+ return lhs > rhs;
+ return lhs < rhs; }
+ case T_IF: {
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d: if(condition) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ const QString cond = args.first();
+ const QChar *d = cond.unicode();
+ QChar quote = 0;
+ bool ret = true, or_op = false;
+ QString test;
+ for(int d_off = 0, parens = 0, d_len = cond.size(); d_off < d_len; ++d_off) {
+ if(!quote.isNull()) {
+ if(*(d+d_off) == quote)
+ quote = QChar();
+ } else if(*(d+d_off) == '(') {
+ ++parens;
+ } else if(*(d+d_off) == ')') {
+ --parens;
+ } else if(*(d+d_off) == '"' /*|| *(d+d_off) == '\''*/) {
+ quote = *(d+d_off);
+ }
+ if(!parens && quote.isNull() && (*(d+d_off) == QLatin1Char(':') || *(d+d_off) == QLatin1Char('|') || d_off == d_len-1)) {
+ if(d_off == d_len-1)
+ test += *(d+d_off);
+ if(!test.isEmpty()) {
+ if (or_op != ret)
+ ret = doProjectTest(test, place);
+ test.clear();
+ }
+ if(*(d+d_off) == QLatin1Char(':')) {
+ or_op = false;
+ } else if(*(d+d_off) == QLatin1Char('|')) {
+ or_op = true;
+ }
+ } else {
+ test += *(d+d_off);
+ }
+ }
+ return ret; }
+ case T_EQUALS:
+ if(args.count() != 2) {
+ fprintf(stderr, "%s:%d: %s(variable, value) requires two arguments.\n", parser.file.toLatin1().constData(),
+ parser.line_no, func.toLatin1().constData());
+ return false;
+ }
+ return values(args[0], place).join(QString(Option::field_sep)) == args[1];
+ case T_EXISTS: {
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d: exists(file) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ QString file = args.first();
+ file = Option::fixPathToLocalOS(file);
+
+ if(QFile::exists(file))
+ return true;
+ //regular expression I guess
+ QString dirstr = qmake_getpwd();
+ int slsh = file.lastIndexOf(QDir::separator());
+ if(slsh != -1) {
+ dirstr = file.left(slsh+1);
+ file = file.right(file.length() - slsh - 1);
+ }
+ return QDir(dirstr).entryList(QStringList(file)).count(); }
+ case T_EXPORT:
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d: export(variable) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ for(int i = 0; i < function_blocks.size(); ++i) {
+ FunctionBlock *f = function_blocks.at(i);
+ f->vars[args[0]] = values(args[0], place);
+ if(!i && f->calling_place)
+ (*f->calling_place)[args[0]] = values(args[0], place);
+ }
+ return true;
+ case T_CLEAR:
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d: clear(variable) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ if(!place.contains(args[0]))
+ return false;
+ place[args[0]].clear();
+ return true;
+ case T_UNSET:
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d: unset(variable) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ if(!place.contains(args[0]))
+ return false;
+ place.remove(args[0]);
+ return true;
+ case T_EVAL: {
+ if(args.count() < 1 && 0) {
+ fprintf(stderr, "%s:%d: eval(project) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ QString project = args.join(" ");
+ parser_info pi = parser;
+ parser.from_file = false;
+ parser.file = "(eval)";
+ parser.line_no = 0;
+ QTextStream t(&project, QIODevice::ReadOnly);
+ bool ret = read(t, place);
+ parser = pi;
+ return ret; }
+ case T_CONFIG: {
+ if(args.count() < 1 || args.count() > 2) {
+ fprintf(stderr, "%s:%d: CONFIG(config) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ if(args.count() == 1)
+ return isActiveConfig(args[0]);
+ const QStringList mutuals = args[1].split('|');
+ const QStringList &configs = values("CONFIG", place);
+ for(int i = configs.size()-1; i >= 0; i--) {
+ for(int mut = 0; mut < mutuals.count(); mut++) {
+ if(configs[i] == mutuals[mut].trimmed())
+ return (configs[i] == args[0]);
+ }
+ }
+ return false; }
+ case T_SYSTEM:
+ if(args.count() < 1 || args.count() > 2) {
+ fprintf(stderr, "%s:%d: system(exec) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ if(args.count() == 2) {
+ const QString sarg = args[1];
+ if (sarg.toLower() == "true" || sarg.toInt())
+ warn_msg(WarnParser, "%s:%d: system()'s second argument is now hard-wired to false.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ }
+ return system(args[0].toLatin1().constData()) == 0;
+ case T_RETURN:
+ if(function_blocks.isEmpty()) {
+ fprintf(stderr, "%s:%d unexpected return()\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ FunctionBlock *f = function_blocks.top();
+ f->cause_return = true;
+ if(args_list.count() >= 1)
+ f->return_value += args_list[0];
+ }
+ return true;
+ case T_BREAK:
+ if(iterator)
+ iterator->cause_break = true;
+ else
+ fprintf(stderr, "%s:%d unexpected break()\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return true;
+ case T_NEXT:
+ if(iterator)
+ iterator->cause_next = true;
+ else
+ fprintf(stderr, "%s:%d unexpected next()\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return true;
+ case T_DEFINED:
+ if(args.count() < 1 || args.count() > 2) {
+ fprintf(stderr, "%s:%d: defined(function) requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ } else {
+ if(args.count() > 1) {
+ if(args[1] == "test")
+ return testFunctions.contains(args[0]);
+ else if(args[1] == "replace")
+ return replaceFunctions.contains(args[0]);
+ fprintf(stderr, "%s:%d: defined(function, type): unexpected type [%s].\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ args[1].toLatin1().constData());
+ } else {
+ if(replaceFunctions.contains(args[0]) || testFunctions.contains(args[0]))
+ return true;
+ }
+ }
+ return false;
+ case T_CONTAINS: {
+ if(args.count() < 2 || args.count() > 3) {
+ fprintf(stderr, "%s:%d: contains(var, val) requires at lesat 2 arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+ QRegExp regx(args[1]);
+ const QStringList &l = values(args[0], place);
+ if(args.count() == 2) {
+ for(int i = 0; i < l.size(); ++i) {
+ const QString val = l[i];
+ if(regx.exactMatch(val) || val == args[1])
+ return true;
+ }
+ } else {
+ const QStringList mutuals = args[2].split('|');
+ for(int i = l.size()-1; i >= 0; i--) {
+ const QString val = l[i];
+ for(int mut = 0; mut < mutuals.count(); mut++) {
+ if(val == mutuals[mut].trimmed())
+ return (regx.exactMatch(val) || val == args[1]);
+ }
+ }
+ }
+ return false; }
+ case T_INFILE: {
+ if(args.count() < 2 || args.count() > 3) {
+ fprintf(stderr, "%s:%d: infile(file, var, val) requires at least 2 arguments.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+
+ bool ret = false;
+ QMap<QString, QStringList> tmp;
+ if(doProjectInclude(Option::fixPathToLocalOS(args[0]), IncludeFlagNewParser, tmp) == IncludeSuccess) {
+ if(tmp.contains("QMAKE_INTERNAL_INCLUDED_FILES")) {
+ QStringList &out = place["QMAKE_INTERNAL_INCLUDED_FILES"];
+ const QStringList &in = tmp["QMAKE_INTERNAL_INCLUDED_FILES"];
+ for(int i = 0; i < in.size(); ++i) {
+ if(out.indexOf(in[i]) == -1)
+ out += in[i];
+ }
+ }
+ if(args.count() == 2) {
+ ret = tmp.contains(args[1]);
+ } else {
+ QRegExp regx(args[2]);
+ const QStringList &l = tmp[args[1]];
+ for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
+ if(regx.exactMatch((*it)) || (*it) == args[2]) {
+ ret = true;
+ break;
+ }
+ }
+ }
+ }
+ return ret; }
+ case T_COUNT:
+ if(args.count() != 2 && args.count() != 3) {
+ fprintf(stderr, "%s:%d: count(var, count) requires two arguments.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ if(args.count() == 3) {
+ QString comp = args[2];
+ if(comp == ">" || comp == "greaterThan")
+ return values(args[0], place).count() > args[1].toInt();
+ if(comp == ">=")
+ return values(args[0], place).count() >= args[1].toInt();
+ if(comp == "<" || comp == "lessThan")
+ return values(args[0], place).count() < args[1].toInt();
+ if(comp == "<=")
+ return values(args[0], place).count() <= args[1].toInt();
+ if(comp == "equals" || comp == "isEqual" || comp == "=" || comp == "==")
+ return values(args[0], place).count() == args[1].toInt();
+ fprintf(stderr, "%s:%d: unexpected modifier to count(%s)\n", parser.file.toLatin1().constData(),
+ parser.line_no, comp.toLatin1().constData());
+ return false;
+ }
+ return values(args[0], place).count() == args[1].toInt();
+ case T_ISEMPTY:
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d: isEmpty(var) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ return values(args[0], place).isEmpty();
+ case T_INCLUDE:
+ case T_LOAD: {
+ QString parseInto;
+ const bool include_statement = (func_t == T_INCLUDE);
+ bool ignore_error = false;
+ if(args.count() >= 2) {
+ if(func_t == T_INCLUDE) {
+ parseInto = args[1];
+ if (args.count() == 3){
+ QString sarg = args[2];
+ if (sarg.toLower() == "true" || sarg.toInt())
+ ignore_error = true;
+ }
+ } else {
+ QString sarg = args[1];
+ ignore_error = (sarg.toLower() == "true" || sarg.toInt());
+ }
+ } else if(args.count() != 1) {
+ QString func_desc = "load(feature)";
+ if(include_statement)
+ func_desc = "include(file)";
+ fprintf(stderr, "%s:%d: %s requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no, func_desc.toLatin1().constData());
+ return false;
+ }
+ QString file = args.first();
+ file = Option::fixPathToLocalOS(file);
+ uchar flags = IncludeFlagNone;
+ if(!include_statement)
+ flags |= IncludeFlagFeature;
+ IncludeStatus stat = IncludeFailure;
+ if(!parseInto.isEmpty()) {
+ QMap<QString, QStringList> symbols;
+ stat = doProjectInclude(file, flags|IncludeFlagNewProject, symbols);
+ if(stat == IncludeSuccess) {
+ QMap<QString, QStringList> out_place;
+ for(QMap<QString, QStringList>::ConstIterator it = place.begin(); it != place.end(); ++it) {
+ const QString var = it.key();
+ if(var != parseInto && !var.startsWith(parseInto + "."))
+ out_place.insert(var, it.value());
+ }
+ for(QMap<QString, QStringList>::ConstIterator it = symbols.begin(); it != symbols.end(); ++it) {
+ const QString var = it.key();
+ if(!var.startsWith("."))
+ out_place.insert(parseInto + "." + it.key(), it.value());
+ }
+ place = out_place;
+ }
+ } else {
+ stat = doProjectInclude(file, flags, place);
+ }
+ if(stat == IncludeFeatureAlreadyLoaded) {
+ warn_msg(WarnParser, "%s:%d: Duplicate of loaded feature %s",
+ parser.file.toLatin1().constData(), parser.line_no, file.toLatin1().constData());
+ } else if(stat == IncludeNoExist && !ignore_error) {
+ warn_msg(WarnAll, "%s:%d: Unable to find file for inclusion %s",
+ parser.file.toLatin1().constData(), parser.line_no, file.toLatin1().constData());
+ return false;
+ } else if(stat >= IncludeFailure) {
+ if(!ignore_error) {
+ printf("Project LOAD(): Feature %s cannot be found.\n", file.toLatin1().constData());
+ if (!ignore_error)
+#if defined(QT_BUILD_QMAKE_LIBRARY)
+ return false;
+#else
+ exit(3);
+#endif
+ }
+ return false;
+ }
+ return true; }
+ case T_DEBUG: {
+ if(args.count() != 2) {
+ fprintf(stderr, "%s:%d: debug(level, message) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no);
+ return false;
+ }
+ QString msg = fixEnvVariables(args[1]);
+ debug_msg(args[0].toInt(), "Project DEBUG: %s", msg.toLatin1().constData());
+ return true; }
+ case T_ERROR:
+ case T_MESSAGE:
+ case T_WARNING: {
+ if(args.count() != 1) {
+ fprintf(stderr, "%s:%d: %s(message) requires one argument.\n", parser.file.toLatin1().constData(),
+ parser.line_no, func.toLatin1().constData());
+ return false;
+ }
+ QString msg = fixEnvVariables(args.first());
+ fprintf(stderr, "Project %s: %s\n", func.toUpper().toLatin1().constData(), msg.toLatin1().constData());
+ if(func == "error")
+#if defined(QT_BUILD_QMAKE_LIBRARY)
+ return false;
+#else
+ exit(2);
+#endif
+ return true; }
+ case T_OPTION:
+ if (args.count() != 1) {
+ fprintf(stderr, "%s:%d: option() requires one argument.\n",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return false;
+ }
+ if (args.first() == "recursive") {
+ recursive = true;
+ } else {
+ fprintf(stderr, "%s:%d: unrecognized option() argument '%s'.\n",
+ parser.file.toLatin1().constData(), parser.line_no,
+ args.first().toLatin1().constData());
+ return false;
+ }
+ return true;
+ default:
+ fprintf(stderr, "%s:%d: Unknown test function: %s\n", parser.file.toLatin1().constData(), parser.line_no,
+ func.toLatin1().constData());
+ }
+ return false;
+}
+
+bool
+QMakeProject::doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringList> &place)
+{
+ bool ret = false;
+ for(QStringList::ConstIterator it = deps.begin(); it != deps.end(); ++it) {
+ bool test = doProjectTest((*it), place);
+ if(!test) {
+ debug_msg(1, "Project Parser: %s:%d Failed test: REQUIRES = %s",
+ parser.file.toLatin1().constData(), parser.line_no,
+ (*it).toLatin1().constData());
+ place["QMAKE_FAILED_REQUIREMENTS"].append((*it));
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+bool
+QMakeProject::test(const QString &v)
+{
+ QMap<QString, QStringList> tmp = vars;
+ return doProjectTest(v, tmp);
+}
+
+bool
+QMakeProject::test(const QString &func, const QList<QStringList> &args)
+{
+ QMap<QString, QStringList> tmp = vars;
+ return doProjectTest(func, args, tmp);
+}
+
+QStringList
+QMakeProject::expand(const QString &str)
+{
+ bool ok;
+ QMap<QString, QStringList> tmp = vars;
+ const QStringList ret = doVariableReplaceExpand(str, tmp, &ok);
+ if(ok)
+ return ret;
+ return QStringList();
+}
+
+QString
+QMakeProject::expand(const QString &str, const QString &file, int line)
+{
+ bool ok;
+ parser_info pi = parser;
+ parser.file = file;
+ parser.line_no = line;
+ parser.from_file = false;
+ QMap<QString, QStringList> tmp = vars;
+ const QStringList ret = doVariableReplaceExpand(str, tmp, &ok);
+ parser = pi;
+ return ok ? ret.join(QString(Option::field_sep)) : QString();
+}
+
+QStringList
+QMakeProject::expand(const QString &func, const QList<QStringList> &args)
+{
+ QMap<QString, QStringList> tmp = vars;
+ return doProjectExpand(func, args, tmp);
+}
+
+bool
+QMakeProject::doVariableReplace(QString &str, QMap<QString, QStringList> &place)
+{
+ bool ret;
+ str = doVariableReplaceExpand(str, place, &ret).join(QString(Option::field_sep));
+ return ret;
+}
+
+QStringList
+QMakeProject::doVariableReplaceExpand(const QString &str, QMap<QString, QStringList> &place, bool *ok)
+{
+ QStringList ret;
+ if(ok)
+ *ok = true;
+ if(str.isEmpty())
+ return ret;
+
+ const ushort LSQUARE = '[';
+ const ushort RSQUARE = ']';
+ const ushort LCURLY = '{';
+ const ushort RCURLY = '}';
+ const ushort LPAREN = '(';
+ const ushort RPAREN = ')';
+ const ushort DOLLAR = '$';
+ const ushort SLASH = '\\';
+ const ushort UNDERSCORE = '_';
+ const ushort DOT = '.';
+ const ushort SPACE = ' ';
+ const ushort TAB = '\t';
+ const ushort SINGLEQUOTE = '\'';
+ const ushort DOUBLEQUOTE = '"';
+
+ ushort unicode, quote = 0;
+ const QChar *str_data = str.data();
+ const int str_len = str.length();
+
+ ushort term;
+ QString var, args;
+
+ int replaced = 0;
+ QString current;
+ for(int i = 0; i < str_len; ++i) {
+ unicode = str_data[i].unicode();
+ const int start_var = i;
+ if(unicode == DOLLAR && str_len > i+2) {
+ unicode = str_data[++i].unicode();
+ if(unicode == DOLLAR) {
+ term = 0;
+ var.clear();
+ args.clear();
+ enum { VAR, ENVIRON, FUNCTION, PROPERTY } var_type = VAR;
+ unicode = str_data[++i].unicode();
+ if(unicode == LSQUARE) {
+ unicode = str_data[++i].unicode();
+ term = RSQUARE;
+ var_type = PROPERTY;
+ } else if(unicode == LCURLY) {
+ unicode = str_data[++i].unicode();
+ var_type = VAR;
+ term = RCURLY;
+ } else if(unicode == LPAREN) {
+ unicode = str_data[++i].unicode();
+ var_type = ENVIRON;
+ term = RPAREN;
+ }
+ while(1) {
+ if(!(unicode & (0xFF<<8)) &&
+ unicode != DOT && unicode != UNDERSCORE &&
+ //unicode != SINGLEQUOTE && unicode != DOUBLEQUOTE &&
+ (unicode < 'a' || unicode > 'z') && (unicode < 'A' || unicode > 'Z') &&
+ (unicode < '0' || unicode > '9'))
+ break;
+ var.append(QChar(unicode));
+ if(++i == str_len)
+ break;
+ unicode = str_data[i].unicode();
+ // at this point, i points to either the 'term' or 'next' character (which is in unicode)
+ }
+ if(var_type == VAR && unicode == LPAREN) {
+ var_type = FUNCTION;
+ int depth = 0;
+ while(1) {
+ if(++i == str_len)
+ break;
+ unicode = str_data[i].unicode();
+ if(unicode == LPAREN) {
+ depth++;
+ } else if(unicode == RPAREN) {
+ if(!depth)
+ break;
+ --depth;
+ }
+ args.append(QChar(unicode));
+ }
+ if(++i < str_len)
+ unicode = str_data[i].unicode();
+ else
+ unicode = 0;
+ // at this point i is pointing to the 'next' character (which is in unicode)
+ // this might actually be a term character since you can do $${func()}
+ }
+ if(term) {
+ if(unicode != term) {
+ qmake_error_msg("Missing " + QString(term) + " terminator [found " + (unicode?QString(unicode):QString("end-of-line")) + "]");
+ if(ok)
+ *ok = false;
+ return QStringList();
+ }
+ } else {
+ // move the 'cursor' back to the last char of the thing we were looking at
+ --i;
+ }
+ // since i never points to the 'next' character, there is no reason for this to be set
+ unicode = 0;
+
+ QStringList replacement;
+ if(var_type == ENVIRON) {
+ replacement = split_value_list(QString::fromLocal8Bit(qgetenv(var.toLatin1().constData())));
+ } else if(var_type == PROPERTY) {
+ if(prop)
+ replacement = split_value_list(prop->value(var));
+ } else if(var_type == FUNCTION) {
+ replacement = doProjectExpand(var, args, place);
+ } else if(var_type == VAR) {
+ replacement = values(var, place);
+ }
+ if(!(replaced++) && start_var)
+ current = str.left(start_var);
+ if(!replacement.isEmpty()) {
+ if(quote) {
+ current += replacement.join(QString(Option::field_sep));
+ } else {
+ current += replacement.takeFirst();
+ if(!replacement.isEmpty()) {
+ if(!current.isEmpty())
+ ret.append(current);
+ current = replacement.takeLast();
+ if(!replacement.isEmpty())
+ ret += replacement;
+ }
+ }
+ }
+ debug_msg(2, "Project Parser [var replace]: %s -> %s",
+ str.toLatin1().constData(), var.toLatin1().constData(),
+ replacement.join("::").toLatin1().constData());
+ } else {
+ if(replaced)
+ current.append("$");
+ }
+ }
+ if(quote && unicode == quote) {
+ unicode = 0;
+ quote = 0;
+ } else if(unicode == SLASH) {
+ bool escape = false;
+ const char *symbols = "[]{}()$\\'\"";
+ for(const char *s = symbols; *s; ++s) {
+ if(str_data[i+1].unicode() == (ushort)*s) {
+ i++;
+ escape = true;
+ if(!(replaced++))
+ current = str.left(start_var);
+ current.append(str.at(i));
+ break;
+ }
+ }
+ if(!escape && !backslashWarned) {
+ backslashWarned = true;
+ warn_msg(WarnDeprecated, "%s:%d: Unescaped backslashes are deprecated.",
+ parser.file.toLatin1().constData(), parser.line_no);
+ }
+ if(escape || !replaced)
+ unicode =0;
+ } else if(!quote && (unicode == SINGLEQUOTE || unicode == DOUBLEQUOTE)) {
+ quote = unicode;
+ unicode = 0;
+ if(!(replaced++) && i)
+ current = str.left(i);
+ } else if(!quote && (unicode == SPACE || unicode == TAB)) {
+ unicode = 0;
+ if(!current.isEmpty()) {
+ ret.append(current);
+ current.clear();
+ }
+ }
+ if(replaced && unicode)
+ current.append(QChar(unicode));
+ }
+ if(!replaced)
+ ret = QStringList(str);
+ else if(!current.isEmpty())
+ ret.append(current);
+ //qDebug() << "REPLACE" << str << ret;
+ if (quote)
+ warn_msg(WarnDeprecated, "%s:%d: Unmatched quotes are deprecated.",
+ parser.file.toLatin1().constData(), parser.line_no);
+ return ret;
+}
+
+QStringList &QMakeProject::values(const QString &_var, QMap<QString, QStringList> &place)
+{
+ QString var = varMap(_var);
+ if(var == QLatin1String("LITERAL_WHITESPACE")) { //a real space in a token)
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(QLatin1String("\t"));
+ } else if(var == QLatin1String("LITERAL_DOLLAR")) { //a real $
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(QLatin1String("$"));
+ } else if(var == QLatin1String("LITERAL_HASH")) { //a real #
+ var = ".BUILTIN." + var;
+ place[var] = QStringList("#");
+ } else if(var == QLatin1String("OUT_PWD")) { //the out going dir
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(Option::output_dir);
+ } else if(var == QLatin1String("PWD") || //current working dir (of _FILE_)
+ var == QLatin1String("IN_PWD")) {
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(qmake_getpwd());
+ } else if(var == QLatin1String("DIR_SEPARATOR")) {
+ validateModes();
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(Option::dir_sep);
+ } else if(var == QLatin1String("DIRLIST_SEPARATOR")) {
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(Option::dirlist_sep);
+ } else if(var == QLatin1String("_LINE_")) { //parser line number
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(QString::number(parser.line_no));
+ } else if(var == QLatin1String("_FILE_")) { //parser file
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(parser.file);
+ } else if(var == QLatin1String("_DATE_")) { //current date/time
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(QDateTime::currentDateTime().toString());
+ } else if(var == QLatin1String("_PRO_FILE_")) {
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(pfile);
+ } else if(var == QLatin1String("_PRO_FILE_PWD_")) {
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(pfile.isEmpty() ? qmake_getpwd() : QFileInfo(pfile).absolutePath());
+ } else if(var == QLatin1String("_QMAKE_CACHE_")) {
+ var = ".BUILTIN." + var;
+ if(Option::mkfile::do_cache)
+ place[var] = QStringList(Option::mkfile::cachefile);
+ } else if(var == QLatin1String("TEMPLATE")) {
+ if(!Option::user_template.isEmpty()) {
+ var = ".BUILTIN.USER." + var;
+ place[var] = QStringList(Option::user_template);
+ } else {
+ QString orig_template, real_template;
+ if(!place[var].isEmpty())
+ orig_template = place[var].first();
+ real_template = orig_template.isEmpty() ? "app" : orig_template;
+ if(!Option::user_template_prefix.isEmpty() && !orig_template.startsWith(Option::user_template_prefix))
+ real_template.prepend(Option::user_template_prefix);
+ if(real_template != orig_template) {
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(real_template);
+ }
+ }
+ } else if(var.startsWith(QLatin1String("QMAKE_HOST."))) {
+ QString ret, type = var.mid(11);
+#if defined(Q_OS_WIN32)
+ if(type == "os") {
+ ret = "Windows";
+ } else if(type == "name") {
+ DWORD name_length = 1024;
+ wchar_t name[1024];
+ if (GetComputerName(name, &name_length))
+ ret = QString::fromWCharArray(name);
+ } else if(type == "version" || type == "version_string") {
+ QSysInfo::WinVersion ver = QSysInfo::WindowsVersion;
+ if(type == "version")
+ ret = QString::number(ver);
+ else if(ver == QSysInfo::WV_Me)
+ ret = "WinMe";
+ else if(ver == QSysInfo::WV_95)
+ ret = "Win95";
+ else if(ver == QSysInfo::WV_98)
+ ret = "Win98";
+ else if(ver == QSysInfo::WV_NT)
+ ret = "WinNT";
+ else if(ver == QSysInfo::WV_2000)
+ ret = "Win2000";
+ else if(ver == QSysInfo::WV_2000)
+ ret = "Win2003";
+ else if(ver == QSysInfo::WV_XP)
+ ret = "WinXP";
+ else if(ver == QSysInfo::WV_VISTA)
+ ret = "WinVista";
+ else
+ ret = "Unknown";
+ } else if(type == "arch") {
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ switch(info.wProcessorArchitecture) {
+#ifdef PROCESSOR_ARCHITECTURE_AMD64
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ ret = "x86_64";
+ break;
+#endif
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ ret = "x86";
+ break;
+ case PROCESSOR_ARCHITECTURE_IA64:
+#ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
+ case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
+#endif
+ ret = "IA64";
+ break;
+ default:
+ ret = "Unknown";
+ break;
+ }
+ }
+#elif defined(Q_OS_UNIX)
+ struct utsname name;
+ if(!uname(&name)) {
+ if(type == "os")
+ ret = name.sysname;
+ else if(type == "name")
+ ret = name.nodename;
+ else if(type == "version")
+ ret = name.release;
+ else if(type == "version_string")
+ ret = name.version;
+ else if(type == "arch")
+ ret = name.machine;
+ }
+#endif
+ var = ".BUILTIN.HOST." + type;
+ place[var] = QStringList(ret);
+ } else if (var == QLatin1String("QMAKE_DIR_SEP")) {
+ if (place[var].isEmpty())
+ return values("DIR_SEPARATOR", place);
+ } else if (var == QLatin1String("QMAKE_EXT_OBJ")) {
+ if (place[var].isEmpty()) {
+ var = ".BUILTIN." + var;
+ place[var] = QStringList(Option::obj_ext);
+ }
+ } else if (var == QLatin1String("QMAKE_QMAKE")) {
+ if (place[var].isEmpty())
+ place[var] = QStringList(Option::fixPathToTargetOS(
+ !Option::qmake_abslocation.isEmpty()
+ ? Option::qmake_abslocation
+ : QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmake",
+ false));
+ } else if (var == QLatin1String("EPOCROOT")) {
+ if (place[var].isEmpty())
+ place[var] = QStringList(qt_epocRoot());
+ }
+#if defined(Q_OS_WIN32) && defined(Q_CC_MSVC)
+ else if(var.startsWith(QLatin1String("QMAKE_TARGET."))) {
+ QString ret, type = var.mid(13);
+ if(type == "arch") {
+ QString paths = qgetenv("PATH");
+ QString vcBin64 = qgetenv("VCINSTALLDIR").append("\\bin\\amd64");
+ QString vcBinX86_64 = qgetenv("VCINSTALLDIR").append("\\bin\\x86_amd64");
+ if(paths.contains(vcBin64,Qt::CaseInsensitive) || paths.contains(vcBinX86_64,Qt::CaseInsensitive))
+ ret = "x86_64";
+ else
+ ret = "x86";
+ }
+ place[var] = QStringList(ret);
+ }
+#endif
+ //qDebug("REPLACE [%s]->[%s]", qPrintable(var), qPrintable(place[var].join("::")));
+ return place[var];
+}
+
+bool QMakeProject::isEmpty(const QString &v)
+{
+ QMap<QString, QStringList>::ConstIterator it = vars.constFind(varMap(v));
+ return it == vars.constEnd() || it->isEmpty();
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/project.h b/qmake/project.h
new file mode 100644
index 0000000000..0e6131d3a2
--- /dev/null
+++ b/qmake/project.h
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** 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 PROJECT_H
+#define PROJECT_H
+
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qstring.h>
+#include <qstack.h>
+#include <qmap.h>
+#include <qmetatype.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMakeProperty;
+
+struct ParsableBlock;
+struct IteratorBlock;
+struct FunctionBlock;
+
+class QMakeProject
+{
+ struct ScopeBlock
+ {
+ enum TestStatus { TestNone, TestFound, TestSeek };
+ ScopeBlock() : iterate(0), ignore(false), else_status(TestNone) { }
+ ScopeBlock(bool i) : iterate(0), ignore(i), else_status(TestNone) { }
+ ~ScopeBlock();
+ IteratorBlock *iterate;
+ uint ignore : 1, else_status : 2;
+ };
+ friend struct ParsableBlock;
+ friend struct IteratorBlock;
+ friend struct FunctionBlock;
+
+ QStack<ScopeBlock> scope_blocks;
+ QStack<FunctionBlock *> function_blocks;
+ IteratorBlock *iterator;
+ FunctionBlock *function;
+ QMap<QString, FunctionBlock*> testFunctions, replaceFunctions;
+
+ bool recursive;
+ bool own_prop;
+ bool backslashWarned;
+ QString pfile, cfile;
+ QMakeProperty *prop;
+ void reset();
+ QMap<QString, QStringList> vars, base_vars, cache;
+ bool parse(const QString &text, QMap<QString, QStringList> &place, int line_count=1);
+
+ enum IncludeStatus {
+ IncludeSuccess,
+ IncludeFeatureAlreadyLoaded,
+ IncludeFailure,
+ IncludeNoExist,
+ IncludeParseFailure
+ };
+ enum IncludeFlags {
+ IncludeFlagNone = 0x00,
+ IncludeFlagFeature = 0x01,
+ IncludeFlagNewParser = 0x02,
+ IncludeFlagNewProject = 0x04
+ };
+ IncludeStatus doProjectInclude(QString file, uchar flags, QMap<QString, QStringList> &place);
+
+ bool doProjectCheckReqs(const QStringList &deps, QMap<QString, QStringList> &place);
+ bool doVariableReplace(QString &str, QMap<QString, QStringList> &place);
+ QStringList doVariableReplaceExpand(const QString &str, QMap<QString, QStringList> &place, bool *ok=0);
+ void init(QMakeProperty *, const QMap<QString, QStringList> *);
+ QStringList &values(const QString &v, QMap<QString, QStringList> &place);
+ void validateModes();
+
+public:
+ QMakeProject() { init(0, 0); }
+ QMakeProject(QMakeProperty *p) { init(p, 0); }
+ QMakeProject(QMakeProject *p, const QMap<QString, QStringList> *nvars=0);
+ QMakeProject(const QMap<QString, QStringList> &nvars) { init(0, &nvars); }
+ QMakeProject(QMakeProperty *p, const QMap<QString, QStringList> &nvars) { init(p, &nvars); }
+ ~QMakeProject();
+
+ enum { ReadCache=0x01, ReadConf=0x02, ReadCmdLine=0x04, ReadProFile=0x08,
+ ReadFeatures=0x20, ReadConfigs=0x40, ReadAll=0xFF };
+ inline bool parse(const QString &text) { return parse(text, vars); }
+ bool read(const QString &project, uchar cmd=ReadAll);
+ bool read(uchar cmd=ReadAll);
+
+ QStringList userExpandFunctions() { return replaceFunctions.keys(); }
+ QStringList userTestFunctions() { return testFunctions.keys(); }
+
+ QString projectFile();
+ inline QMakeProperty *properties() { return prop; }
+
+ bool doProjectTest(QString str, QMap<QString, QStringList> &place);
+ bool doProjectTest(QString func, const QString &params,
+ QMap<QString, QStringList> &place);
+ bool doProjectTest(QString func, QStringList args,
+ QMap<QString, QStringList> &place);
+ bool doProjectTest(QString func, QList<QStringList> args,
+ QMap<QString, QStringList> &place);
+ QStringList doProjectExpand(QString func, const QString &params,
+ QMap<QString, QStringList> &place);
+ QStringList doProjectExpand(QString func, QStringList args,
+ QMap<QString, QStringList> &place);
+ QStringList doProjectExpand(QString func, QList<QStringList> args,
+ QMap<QString, QStringList> &place);
+
+ QStringList expand(const QString &v);
+ QString expand(const QString &v, const QString &file, int line);
+ QStringList expand(const QString &func, const QList<QStringList> &args);
+ bool test(const QString &v);
+ bool test(const QString &func, const QList<QStringList> &args);
+ bool isActiveConfig(const QString &x, bool regex=false,
+ QMap<QString, QStringList> *place=NULL);
+
+ bool isSet(const QString &v); // No compat mapping, no magic variables
+ bool isEmpty(const QString &v); // With compat mapping, but no magic variables
+ QStringList &values(const QString &v); // With compat mapping and magic variables
+ QString first(const QString &v); // ditto
+ QMap<QString, QStringList> &variables(); // No compat mapping and magic, obviously
+
+ bool isRecursive() const { return recursive; }
+
+protected:
+ friend class MakefileGenerator;
+ bool read(const QString &file, QMap<QString, QStringList> &place);
+ bool read(QTextStream &file, QMap<QString, QStringList> &place);
+
+};
+Q_DECLARE_METATYPE(QMakeProject*)
+
+inline QString QMakeProject::projectFile()
+{
+ if (pfile == "-")
+ return QString("(stdin)");
+ return pfile;
+}
+
+inline QStringList &QMakeProject::values(const QString &v)
+{ return values(v, vars); }
+
+inline bool QMakeProject::isSet(const QString &v)
+{ return vars.contains(v); }
+
+inline QString QMakeProject::first(const QString &v)
+{
+ const QStringList vals = values(v);
+ if(vals.isEmpty())
+ return QString("");
+ return vals.first();
+}
+
+inline QMap<QString, QStringList> &QMakeProject::variables()
+{ return vars; }
+
+QT_END_NAMESPACE
+
+#endif // PROJECT_H
diff --git a/qmake/property.cpp b/qmake/property.cpp
new file mode 100644
index 0000000000..0c36c1cc59
--- /dev/null
+++ b/qmake/property.cpp
@@ -0,0 +1,251 @@
+/****************************************************************************
+**
+** 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 "property.h"
+#include "option.h"
+
+#include <qdir.h>
+#include <qmap.h>
+#include <qsettings.h>
+#include <qstringlist.h>
+#include <stdio.h>
+
+QT_BEGIN_NAMESPACE
+
+QStringList qmake_mkspec_paths(); //project.cpp
+
+QMakeProperty::QMakeProperty() : settings(0)
+{
+}
+
+QMakeProperty::~QMakeProperty()
+{
+ delete settings;
+ settings = 0;
+}
+
+void QMakeProperty::initSettings()
+{
+ if(!settings) {
+ settings = new QSettings(QSettings::UserScope, "Trolltech", "QMake");
+ settings->setFallbacksEnabled(false);
+ }
+}
+
+QString
+QMakeProperty::keyBase(bool version) const
+{
+ if (version)
+ return QString(qmake_version()) + "/";
+ return QString();
+}
+
+QString
+QMakeProperty::value(QString v, bool just_check)
+{
+ if(v == "QT_INSTALL_PREFIX")
+ return QLibraryInfo::location(QLibraryInfo::PrefixPath);
+ else if(v == "QT_INSTALL_DATA")
+ return QLibraryInfo::location(QLibraryInfo::DataPath);
+ else if(v == "QT_INSTALL_DOCS")
+ return QLibraryInfo::location(QLibraryInfo::DocumentationPath);
+ else if(v == "QT_INSTALL_HEADERS")
+ return QLibraryInfo::location(QLibraryInfo::HeadersPath);
+ else if(v == "QT_INSTALL_LIBS")
+ return QLibraryInfo::location(QLibraryInfo::LibrariesPath);
+ else if(v == "QT_INSTALL_BINS")
+ return QLibraryInfo::location(QLibraryInfo::BinariesPath);
+ else if(v == "QT_INSTALL_PLUGINS")
+ return QLibraryInfo::location(QLibraryInfo::PluginsPath);
+ else if(v == "QT_INSTALL_IMPORTS")
+ return QLibraryInfo::location(QLibraryInfo::ImportsPath);
+ else if(v == "QT_INSTALL_TRANSLATIONS")
+ return QLibraryInfo::location(QLibraryInfo::TranslationsPath);
+ else if(v == "QT_INSTALL_CONFIGURATION")
+ return QLibraryInfo::location(QLibraryInfo::SettingsPath);
+ else if(v == "QT_INSTALL_EXAMPLES")
+ return QLibraryInfo::location(QLibraryInfo::ExamplesPath);
+ else if(v == "QT_INSTALL_DEMOS")
+ return QLibraryInfo::location(QLibraryInfo::DemosPath);
+ else if(v == "QMAKE_MKSPECS")
+ return qmake_mkspec_paths().join(Option::dirlist_sep);
+ else if(v == "QMAKE_VERSION")
+ return qmake_version();
+#ifdef QT_VERSION_STR
+ else if(v == "QT_VERSION")
+ return QT_VERSION_STR;
+#endif
+
+ initSettings();
+ int slash = v.lastIndexOf('/');
+ QVariant var = settings->value(keyBase(slash == -1) + v);
+ bool ok = var.isValid();
+ QString ret = var.toString();
+ if(!ok) {
+ QString version = qmake_version();
+ if(slash != -1) {
+ version = v.left(slash-1);
+ v = v.mid(slash+1);
+ }
+ settings->beginGroup(keyBase(false));
+ QStringList subs = settings->childGroups();
+ settings->endGroup();
+ subs.sort();
+ for (int x = subs.count() - 1; x >= 0; x--) {
+ QString s = subs[x];
+ if(s.isEmpty() || s > version)
+ continue;
+ var = settings->value(keyBase(false) + s + "/" + v);
+ ok = var.isValid();
+ ret = var.toString();
+ if (ok) {
+ if(!just_check)
+ debug_msg(1, "Fell back from %s -> %s for '%s'.", version.toLatin1().constData(),
+ s.toLatin1().constData(), v.toLatin1().constData());
+ return ret;
+ }
+ }
+ }
+ return ok ? ret : QString();
+}
+
+bool
+QMakeProperty::hasValue(QString v)
+{
+ return !value(v, true).isNull();
+}
+
+void
+QMakeProperty::setValue(QString var, const QString &val)
+{
+ initSettings();
+ settings->setValue(keyBase() + var, val);
+}
+
+void
+QMakeProperty::remove(const QString &var)
+{
+ initSettings();
+ settings->remove(keyBase() + var);
+}
+
+bool
+QMakeProperty::exec()
+{
+ bool ret = true;
+ if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY) {
+ if(Option::prop::properties.isEmpty()) {
+ initSettings();
+ settings->beginGroup(keyBase(false));
+ QStringList subs = settings->childGroups();
+ settings->endGroup();
+ subs.sort();
+ for(int x = subs.count() - 1; x >= 0; x--) {
+ QString s = subs[x];
+ if(s.isEmpty())
+ continue;
+ settings->beginGroup(keyBase(false) + s);
+ QStringList keys = settings->childKeys();
+ settings->endGroup();
+ for(QStringList::ConstIterator it2 = keys.begin(); it2 != keys.end(); it2++) {
+ QString ret = settings->value(keyBase(false) + s + "/" + (*it2)).toString();
+ if(s != qmake_version())
+ fprintf(stdout, "%s/", s.toLatin1().constData());
+ fprintf(stdout, "%s:%s\n", (*it2).toLatin1().constData(), ret.toLatin1().constData());
+ }
+ }
+ QStringList specialProps;
+ specialProps.append("QT_INSTALL_PREFIX");
+ specialProps.append("QT_INSTALL_DATA");
+ specialProps.append("QT_INSTALL_DOCS");
+ specialProps.append("QT_INSTALL_HEADERS");
+ specialProps.append("QT_INSTALL_LIBS");
+ specialProps.append("QT_INSTALL_BINS");
+ specialProps.append("QT_INSTALL_PLUGINS");
+ specialProps.append("QT_INSTALL_IMPORTS");
+ specialProps.append("QT_INSTALL_TRANSLATIONS");
+ specialProps.append("QT_INSTALL_CONFIGURATION");
+ specialProps.append("QT_INSTALL_EXAMPLES");
+ specialProps.append("QT_INSTALL_DEMOS");
+ specialProps.append("QMAKE_MKSPECS");
+ specialProps.append("QMAKE_VERSION");
+#ifdef QT_VERSION_STR
+ specialProps.append("QT_VERSION");
+#endif
+ foreach (QString prop, specialProps)
+ fprintf(stdout, "%s:%s\n", prop.toLatin1().constData(), value(prop).toLatin1().constData());
+ return true;
+ }
+ for(QStringList::ConstIterator it = Option::prop::properties.begin();
+ it != Option::prop::properties.end(); it++) {
+ if(Option::prop::properties.count() > 1)
+ fprintf(stdout, "%s:", (*it).toLatin1().constData());
+ if(!hasValue((*it))) {
+ ret = false;
+ fprintf(stdout, "**Unknown**\n");
+ } else {
+ fprintf(stdout, "%s\n", value((*it)).toLatin1().constData());
+ }
+ }
+ } else if(Option::qmake_mode == Option::QMAKE_SET_PROPERTY) {
+ for(QStringList::ConstIterator it = Option::prop::properties.begin();
+ it != Option::prop::properties.end(); it++) {
+ QString var = (*it);
+ it++;
+ if(it == Option::prop::properties.end()) {
+ ret = false;
+ break;
+ }
+ if(!var.startsWith("."))
+ setValue(var, (*it));
+ }
+ } else if(Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY) {
+ for(QStringList::ConstIterator it = Option::prop::properties.begin();
+ it != Option::prop::properties.end(); it++) {
+ QString var = (*it);
+ if(!var.startsWith("."))
+ remove(var);
+ }
+ }
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/property.h b/qmake/property.h
new file mode 100644
index 0000000000..5e8379e787
--- /dev/null
+++ b/qmake/property.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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 PROPERTY_H
+#define PROPERTY_H
+
+#include <qglobal.h>
+#include <qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSettings;
+
+class QMakeProperty
+{
+ QSettings *settings;
+ void initSettings();
+ QString keyBase(bool =true) const;
+ QString value(QString, bool just_check);
+public:
+ QMakeProperty();
+ ~QMakeProperty();
+
+ bool hasValue(QString);
+ QString value(QString v) { return value(v, false); }
+ void setValue(QString, const QString &);
+ void remove(const QString &);
+
+ bool exec();
+};
+
+QT_END_NAMESPACE
+
+#endif // PROPERTY_H
diff --git a/qmake/qmake.pri b/qmake/qmake.pri
new file mode 100644
index 0000000000..d6c5f09107
--- /dev/null
+++ b/qmake/qmake.pri
@@ -0,0 +1,162 @@
+CONFIG += depend_includepath
+
+QMAKE_INCREMENTAL =
+SKIP_DEPENDS += qconfig.h qmodules.h
+DEFINES += QT_NO_TEXTCODEC QT_NO_LIBRARY QT_NO_STL QT_NO_COMPRESS QT_NO_UNICODETABLES \
+ QT_NO_GEOM_VARIANT QT_NO_DATASTREAM QLIBRARYINFO_EPOCROOT
+
+#qmake code
+SOURCES += project.cpp property.cpp main.cpp generators/makefile.cpp \
+ generators/unix/unixmake2.cpp generators/unix/unixmake.cpp meta.cpp \
+ option.cpp generators/win32/winmakefile.cpp generators/win32/mingw_make.cpp \
+ generators/makefiledeps.cpp generators/metamakefile.cpp generators/mac/pbuilder_pbx.cpp \
+ generators/xmloutput.cpp generators/win32/borland_bmake.cpp \
+ generators/win32/msvc_nmake.cpp generators/projectgenerator.cpp \
+ generators/win32/msvc_vcproj.cpp \
+ generators/win32/msvc_vcxproj.cpp \
+ generators/win32/msvc_objectmodel.cpp generators/win32/msbuild_objectmodel.cpp \
+ generators/symbian/symbiancommon.cpp \
+ generators/symbian/symmake.cpp \
+ generators/symbian/symmake_abld.cpp \
+ generators/symbian/symmake_sbsv2.cpp \
+ generators/symbian/initprojectdeploy_symbian.cpp \
+ windows/registry.cpp \
+ symbian/epocroot.cpp
+
+HEADERS += project.h property.h generators/makefile.h \
+ generators/unix/unixmake.h meta.h option.h cachekeys.h \
+ generators/win32/winmakefile.h generators/win32/mingw_make.h generators/projectgenerator.h \
+ generators/makefiledeps.h generators/metamakefile.h generators/mac/pbuilder_pbx.h \
+ generators/xmloutput.h generators/win32/borland_bmake.h generators/win32/msvc_nmake.h \
+ generators/win32/msvc_vcproj.h \
+ generators/win32/msvc_vcxproj.h \
+ generators/win32/msvc_objectmodel.h generators/win32/msbuild_objectmodel.h \
+ generators/symbian/symbiancommon.h \
+ generators/symbian/symmake.h \
+ generators/symbian/symmake_abld.h \
+ generators/symbian/symmake_sbsv2.h \
+ generators/symbian/initprojectdeploy_symbian.h \
+ windows/registry_p.h \
+ symbian/epocroot_p.h
+
+contains(QT_EDITION, OpenSource) {
+ DEFINES += QMAKE_OPENSOURCE_EDITION
+}
+
+bootstrap { #Qt code
+ DEFINES+=QT_NODLL QT_NO_THREAD
+ SOURCES+= \
+ qbitarray.cpp \
+ qbuffer.cpp \
+ qbytearray.cpp \
+ qbytearraymatcher.cpp \
+ qcryptographichash.cpp \
+ qdatetime.cpp \
+ qdir.cpp \
+ qdiriterator.cpp \
+ qfile.cpp \
+ qabstractfileengine.cpp \
+ qfileinfo.cpp \
+ qfilesystementry.cpp \
+ qfilesystemengine.cpp \
+ qfsfileengine.cpp \
+ qfsfileengine_iterator.cpp \
+ qglobal.cpp \
+ qnumeric.cpp \
+ qhash.cpp \
+ qiodevice.cpp \
+ qlist.cpp \
+ qlinkedlist.cpp \
+ qlocale.cpp \
+ qmalloc.cpp \
+ qmap.cpp \
+ qmetatype.cpp \
+ qregexp.cpp \
+ qtextcodec.cpp \
+ qutfcodec.cpp \
+ qstring.cpp \
+ qstringlist.cpp \
+ qtemporaryfile.cpp \
+ qtextstream.cpp \
+ qurl.cpp \
+ quuid.cpp \
+ qsettings.cpp \
+ qlibraryinfo.cpp \
+ qsystemerror.cpp \
+ qvariant.cpp \
+ qvector.cpp \
+ qvsnprintf.cpp \
+ qxmlstream.cpp \
+ qxmlutils.cpp
+
+ HEADERS+= \
+ qbitarray.h \
+ qbuffer.h \
+ qbytearray.h \
+ qbytearraymatcher.h \
+ qchar.h \
+ qcryptographichash.h \
+ qdatetime.h \
+ qdatetime_p.h \
+ qdir.h \
+ qdir_p.h \
+ qdiriterator.h \
+ qfile.h \
+ qabstractfileengine.h \
+ qfileinfo.h \
+ qglobal.h \
+ qnumeric.h \
+ qhash.h \
+ qiodevice.h \
+ qlist.h \
+ qlinkedlist.h \
+ qlocale.h \
+ qmalloc.h \
+ qmap.h \
+ qmetatype.h \
+ qregexp.h \
+ qtextcodec.h \
+ qutfcodec.h \
+ qstring.h \
+ qstringlist.h \
+ qstringmatcher.h \
+ qsystemerror_p.h \
+ qtemporaryfile.h \
+ qtextstream.h \
+ qurl.h \
+ quuid.h \
+ qvector.h \
+ qxmlstream.h \
+ qxmlutils.h
+
+ unix {
+ SOURCES += qfilesystemengine_unix.cpp qfilesystemiterator_unix.cpp qfsfileengine_unix.cpp
+ mac {
+ SOURCES += qfilesystemengine_mac.cpp
+ SOURCES += qcore_mac.cpp qsettings_mac.cpp
+ QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 #enables weak linking for 10.4 (exported)
+ LIBS += -framework ApplicationServices
+ }
+ } else:win32 {
+ SOURCES += qfilesystemengine_win.cpp qfsfileengine_win.cpp qfilesystemiterator_win.cpp qsettings_win.cpp \
+ qsystemlibrary.cpp
+ win32-msvc*:LIBS += ole32.lib advapi32.lib
+ win32-g++*:LIBS += -lole32 -luuid -ladvapi32 -lkernel32
+ }
+
+ qnx {
+ CFLAGS += -fhonor-std
+ LFLAGS += -lcpp
+ }
+ DEFINES *= QT_NO_QOBJECT
+} else {
+ CONFIG += qt
+ QT = core
+}
+*-g++:profiling {
+ QMAKE_CFLAGS = -pg
+ QMAKE_CXXFLAGS = -pg
+ QMAKE_LFLAGS = -pg
+}
+
+PRECOMPILED_HEADER = qmake_pch.h
diff --git a/qmake/qmake.pro b/qmake/qmake.pro
new file mode 100644
index 0000000000..b602afa198
--- /dev/null
+++ b/qmake/qmake.pro
@@ -0,0 +1,36 @@
+#This is a project file for building qmake, of course it presents a problem -
+# it is very hard to make qmake build this, when qmake is the thing it builds,
+#once you are boot strapped though, the qmake.pro will offer better coverage of a
+#platform than either of the generic makefiles
+
+CONFIG += console bootstrap
+CONFIG -= qt shared app_bundle uic
+DEFINES += QT_BUILD_QMAKE QT_BOOTSTRAPPED
+DESTDIR = ../bin/
+
+OBJECTS_DIR = .
+MOC_DIR = .
+
+#guts
+VPATH += $$QT_SOURCE_TREE/src/corelib/global \
+ $$QT_SOURCE_TREE/src/corelib/tools \
+ $$QT_SOURCE_TREE/src/corelib/kernel \
+ $$QT_SOURCE_TREE/src/corelib/codecs \
+ $$QT_SOURCE_TREE/src/corelib/plugin \
+ $$QT_SOURCE_TREE/src/corelib/xml \
+ $$QT_SOURCE_TREE/src/corelib/io
+INCLUDEPATH += . \
+ generators \
+ generators/unix \
+ generators/win32 \
+ generators/mac \
+ generators/symbian \
+ $$QT_SOURCE_TREE/include \
+ $$QT_SOURCE_TREE/include/QtCore \
+ $$QT_SOURCE_TREE/qmake
+
+VPATH += $$QT_SOURCE_TREE/tools/shared
+INCLUDEPATH += $$QT_SOURCE_TREE/tools/shared
+
+include(qmake.pri)
+
diff --git a/qmake/qmake_pch.h b/qmake/qmake_pch.h
new file mode 100644
index 0000000000..25f27160a1
--- /dev/null
+++ b/qmake/qmake_pch.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 QMAKE_PCH_H
+#define QMAKE_PCH_H
+#include <qglobal.h>
+#ifdef Q_WS_WIN
+# define _POSIX_
+# include <limits.h>
+# undef _POSIX_
+#endif
+
+#include <stdio.h>
+//#include "makefile.h"
+//#include "meta.h"
+#include <qfile.h>
+//#include "winmakefile.h"
+//#include <qtextstream.h>
+//#include "project.h"
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qhash.h>
+#include <time.h>
+#include <stdlib.h>
+#include <qregexp.h>
+
+QT_BEGIN_NAMESPACE
+//#include <qdir.h>
+//#include "option.h"
+
+QT_END_NAMESPACE
+
+#endif