Bug 1408675 p1. Set Eclipse CDT per-directory defines in the right place. r=botond
authorJonathan Watt <jwatt@jwatt.org>
Wed, 31 Oct 2018 10:02:35 +0000
changeset 503552 58bb44b8cbba05ecdc9bb23cd826fd90f3a88969
parent 503551 9d92116a6e98e57ed4be283eb13d21984db886fd
child 503553 ab9d9c4cd361557ea0f07e71e6b1a10fb0585938
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1408675
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1408675 p1. Set Eclipse CDT per-directory defines in the right place. r=botond We've been setting per-directory defines in the "CDT Managed Build Setting Entries" which are ignored(!) during indexing since we don't use the Eclipse managed build system (we use mach). We need to set the defines as "CDT User Setting Entries". Differential Revision: https://phabricator.services.mozilla.com/D12008
python/mozbuild/mozbuild/backend/cpp_eclipse.py
--- a/python/mozbuild/mozbuild/backend/cpp_eclipse.py
+++ b/python/mozbuild/mozbuild/backend/cpp_eclipse.py
@@ -5,16 +5,17 @@
 from __future__ import absolute_import
 
 import errno
 import random
 import os
 import shutil
 import subprocess
 import types
+from xml.sax.saxutils import quoteattr
 import xml.etree.ElementTree as ET
 from .common import CommonBackend
 
 from ..frontend.data import (
     Defines,
 )
 from mozbuild.base import ExecutionSummary
 
@@ -194,34 +195,87 @@ class CppEclipseBackend(CommonBackend):
         noindex_path = os.path.join(self._project_dir, '.settings/org.eclipse.cdt.core.prefs')
         # This may fail if the entire tree has been removed; that's fine.
         try:
             os.remove(noindex_path)
         except OSError as e:
             if e.errno != errno.ENOENT:
                 raise
 
-    def _define_entry(self, name, value):
-        define = ET.Element('entry')
-        define.set('kind', 'macro')
-        define.set('name', name)
-        define.set('value', value)
-        return ET.tostring(define)
+    def _write_language_settings(self, fh):
+        def add_objdir_include_path(relpath):
+            p = os.path.join(self.environment.topobjdir, relpath)
+            return LANGUAGE_SETTINGS_TEMPLATE_DIR_INCLUDE.replace("@INCLUDE_PATH@", p)
+
+        def add_define(name, value):
+            define = LANGUAGE_SETTINGS_TEMPLATE_DIR_DEFINE
+            define = define.replace("@NAME@", name)
+            # We use quoteattr here because some defines contain characters
+            # such as "<" and '"' which need proper XML escaping.
+            define = define.replace("@VALUE@", quoteattr(value))
+            return define
+
+        fh.write(LANGUAGE_SETTINGS_TEMPLATE_HEADER)
+
+        # Unfortunately, whenever we set a user defined include path or define
+        # on a directory, Eclipse ignores user defined include paths and defines
+        # on ancestor directories.  That means that we need to add all the
+        # common include paths and defines to every single directory entry that
+        # we add settings for.  (Fortunately that doesn't appear to have a
+        # noticeable impact on the time it takes to open the generated Eclipse
+        # project.)  We do that by generating a template here that we can then
+        # use for each individual directory in the loop below.
+        #
+        dirsettings_template = LANGUAGE_SETTINGS_TEMPLATE_DIR_HEADER
+
+        # Add OS_COMPILE_CXXFLAGS args (same as OS_COMPILE_CFLAGS):
+        dirsettings_template = dirsettings_template.replace('@PREINCLUDE_FILE_PATH@', os.path.join(self.environment.topobjdir, 'dist/include/mozilla-config.h'))
+
+        # Add EXTRA_INCLUDES args:
+        dirsettings_template += add_objdir_include_path('dist/include')
+
+        # Add OS_INCLUDES args:
+        # XXX media/webrtc/trunk/webrtc's moz.builds reset this.
+        dirsettings_template += add_objdir_include_path('dist/include/nspr')
 
-    def _write_language_settings(self, fh):
-        settings = LANGUAGE_SETTINGS_TEMPLATE
+        # Finally, add anything else that makes things work better.
+        #
+        # Because of https://developer.mozilla.org/en-US/docs/Eclipse_CDT#Headers_are_only_parsed_once
+        # we set MOZILLA_INTERNAL_API for all directories to make sure
+        # headers are indexed with MOZILLA_INTERNAL_API set.  Unfortunately
+        # this means that MOZILLA_EXTERNAL_API code will suffer.
+        #
+        # TODO: If we're doing this for MOZILLA_EXTERNAL_API then we may want
+        # to do it for other LIBRARY_DEFINES's defines too.  Well, at least for
+        # STATIC_EXPORTABLE_JS_API which may be important to JS people.
+        # (The other two LIBRARY_DEFINES defines -- MOZ_HAS_MOZGLUE and
+        # IMPL_LIBXUL -- don't affect much and probably don't matter to anyone).
+        #
+        # TODO: Should we also always set DEBUG so that DEBUG code is always
+        # indexed?  Or is there significant amounts of non-DEBUG code that
+        # would be adversely affected?
+        #
+        # TODO: Investigate whether the ordering of directories in the project
+        # file can be used to our advantage so that the first indexing of
+        # important headers has the defines we want.
+        #
+        dirsettings_template += add_objdir_include_path('ipc/ipdl/_ipdlheaders')
+        dirsettings_template += add_define('MOZILLA_INTERNAL_API', '1')
 
-        settings = settings.replace('@GLOBAL_INCLUDE_PATH@', os.path.join(self.environment.topobjdir, 'dist/include'))
-        settings = settings.replace('@NSPR_INCLUDE_PATH@', os.path.join(self.environment.topobjdir, 'dist/include/nspr'))
-        settings = settings.replace('@IPDL_INCLUDE_PATH@', os.path.join(self.environment.topobjdir, 'ipc/ipdl/_ipdlheaders'))
-        settings = settings.replace('@PREINCLUDE_FILE_PATH@', os.path.join(self.environment.topobjdir, 'dist/include/mozilla-config.h'))
-        settings = settings.replace('@DEFINE_MOZILLA_INTERNAL_API@', self._define_entry('MOZILLA_INTERNAL_API', '1'))
-        settings = settings.replace("@COMPILER_FLAGS@", self._cxx + " " + self._cppflags);
+        for path, defines in self._paths_to_defines.items():
+            dirsettings = dirsettings_template
+            dirsettings = dirsettings.replace('@RELATIVE_PATH@', path)
+            for k, v in defines.items():
+                if v == True:
+                    v = ""
+                dirsettings += add_define(k, str(v))
+            dirsettings += LANGUAGE_SETTINGS_TEMPLATE_DIR_FOOTER
+            fh.write(dirsettings)
 
-        fh.write(settings)
+        fh.write(LANGUAGE_SETTINGS_TEMPLATE_FOOTER.replace("@COMPILER_FLAGS@", self._cxx + " " + self._cppflags))
 
     def _write_launch_files(self, launch_dir):
         bin_dir = os.path.join(self.environment.topobjdir, 'dist')
 
         # TODO Improve binary detection
         if self._macbundle:
             exe_path = os.path.join(bin_dir, self._macbundle, 'Contents/MacOS')
         else:
@@ -247,30 +301,16 @@ class CppEclipseBackend(CommonBackend):
         project = project.replace('@GENERATED_WEBIDL_FILES@', os.path.join(self.environment.topobjdir, "dom", "bindings"))
         fh.write(project)
 
     def _write_cproject(self, fh):
         cproject_header = CPROJECT_TEMPLATE_HEADER
         cproject_header = cproject_header.replace('@PROJECT_TOPSRCDIR@', self.environment.topobjdir)
         cproject_header = cproject_header.replace('@MACH_COMMAND@', os.path.join(self.environment.topsrcdir, 'mach'))
         fh.write(cproject_header)
-
-        for path, defines in self._paths_to_defines.items():
-            folderinfo = CPROJECT_TEMPLATE_FOLDER_INFO_HEADER
-            folderinfo = folderinfo.replace('@FOLDER_ID@', str(random.randint(1000000, 99999999999)))
-            folderinfo = folderinfo.replace('@FOLDER_NAME@', 'tree/' + path)
-            fh.write(folderinfo)
-            for k, v in defines.items():
-                define = ET.Element('listOptionValue')
-                define.set('builtIn', 'false')
-                define.set('value', str(k) + "=" + str(v))
-                fh.write(ET.tostring(define))
-            fh.write(CPROJECT_TEMPLATE_FOLDER_INFO_FOOTER)
-
-
         fh.write(CPROJECT_TEMPLATE_FOOTER)
 
 
 PROJECT_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
         <name>@PROJECT_NAME@</name>
         <comment></comment>
         <projects>
@@ -383,33 +423,16 @@ CPROJECT_TEMPLATE_HEADER = """<?xml vers
                                 <configuration artifactName="${ProjName}" buildProperties="" description="" id="0.1674256904" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">
                                         <folderInfo id="0.1674256904." name="/" resourcePath="">
                                                 <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.1276586933" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug">
                                                         <targetPlatform archList="all" binaryParser="" id="cdt.managedbuild.targetPlatform.gnu.cross.710759961" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
 							<builder arguments="--log-no-times build" buildPath="@PROJECT_TOPSRCDIR@" command="@MACH_COMMAND@" enableCleanBuild="false" incrementalBuildTarget="binaries" id="org.eclipse.cdt.build.core.settings.default.builder.1437267827" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
                                                 </toolChain>
                                         </folderInfo>
 """
-CPROJECT_TEMPLATE_FOLDER_INFO_HEADER = """
-					<folderInfo id="0.1674256904.@FOLDER_ID@" name="/" resourcePath="@FOLDER_NAME@">
-						<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.1022318069" name="No ToolChain" superClass="org.eclipse.cdt.build.core.prefbase.toolchain" unusedChildren="">
-							<tool id="org.eclipse.cdt.build.core.settings.holder.libs.1259030812" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs.1800697532"/>
-							<tool id="org.eclipse.cdt.build.core.settings.holder.1407291069" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder.582514939">
-								<option id="org.eclipse.cdt.build.core.settings.holder.symbols.1907658087" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
-"""
-CPROJECT_TEMPLATE_FOLDER_INFO_DEFINE = """
-									<listOptionValue builtIn="false" value="@FOLDER_DEFINE@"/>
-"""
-CPROJECT_TEMPLATE_FOLDER_INFO_FOOTER = """
-								</option>
-								<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.440601711" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
-							</tool>
-						</toolChain>
-					</folderInfo>
-"""
 CPROJECT_TEMPLATE_FILEINFO = """                                        <fileInfo id="0.1674256904.474736658" name="Layers.cpp" rcbsApplicability="disable" resourcePath="tree/gfx/layers/Layers.cpp" toolsToInvoke="org.eclipse.cdt.build.core.settings.holder.582514939.463639939">
                                                 <tool id="org.eclipse.cdt.build.core.settings.holder.582514939.463639939" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder.582514939">
                                                         <option id="org.eclipse.cdt.build.core.settings.holder.symbols.232300236" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
                                                                 <listOptionValue builtIn="false" value="BENWA=BENWAVAL"/>
                                                         </option>
                                                         <inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1942876228" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
                                                 </tool>
                                         </fileInfo>
@@ -445,55 +468,61 @@ WORKSPACE_LANGUAGE_SETTINGS_TEMPLATE = "
                 <provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="true" id="org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings" parameter="@COMPILER_FLAGS@ -E -P -v -dD &quot;${INPUTS}&quot;">
                         <language-scope id="org.eclipse.cdt.core.gcc"/>
                         <language-scope id="org.eclipse.cdt.core.g++"/>
                 </provider>
         </extension>
 </plugin>
 """
 
-LANGUAGE_SETTINGS_TEMPLATE = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+# The settings set via this template can be found in the UI by opening
+# the Properties for a directory in the Project Explorer tab, then going to
+# C/C++ General > Preprocessor Include Paths, Macros, etc., selecting the
+# C++ item from the Languages column, and then expanding the
+# CDT User Settings Entries item to the right.
+
+LANGUAGE_SETTINGS_TEMPLATE_HEADER = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <project>
-        <configuration id="0.1674256904" name="Default">
-                <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
-                        <provider class="org.eclipse.cdt.core.language.settings.providers.LanguageSettingsGenericProvider" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider" name="CDT User Setting Entries" prefer-non-shared="true" store-entries-with-project="true">
-                                <language id="org.eclipse.cdt.core.g++">
-                                        <resource project-relative-path="">
-                                                <entry kind="includePath" name="@GLOBAL_INCLUDE_PATH@">
-                                                        <flag value="LOCAL"/>
-                                                </entry>
-                                                <entry kind="includePath" name="@NSPR_INCLUDE_PATH@">
-                                                        <flag value="LOCAL"/>
-                                                </entry>
-                                                <entry kind="includePath" name="@IPDL_INCLUDE_PATH@">
-                                                        <flag value="LOCAL"/>
-                                                </entry>
-                                                <entry kind="includeFile" name="@PREINCLUDE_FILE_PATH@">
-                                                        <flag value="LOCAL"/>
-                                                </entry>
-                                                <!--
-                                                  Because of https://developer.mozilla.org/en-US/docs/Eclipse_CDT#Headers_are_only_parsed_once
-                                                  we need to make sure headers are parsed with MOZILLA_INTERNAL_API to make sure
-                                                  the indexer gets the version that is used in most of the true. This means that
-                                                  MOZILLA_EXTERNAL_API code will suffer.
-                                                -->
-                                                @DEFINE_MOZILLA_INTERNAL_API@
-                                        </resource>
-                                </language>
-                        </provider>
-                        <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-859273372804152468" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="@COMPILER_FLAGS@ -E -P -v -dD &quot;${INPUTS}&quot; -std=c++11" prefer-non-shared="true" store-entries-with-project="true">
-                             <language-scope id="org.eclipse.cdt.core.gcc"/>
-                             <language-scope id="org.eclipse.cdt.core.g++"/>
-                        </provider>
-                        <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
-                </extension>
-        </configuration>
+	<configuration id="0.1674256904" name="Default">
+		<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+			<provider class="org.eclipse.cdt.core.language.settings.providers.LanguageSettingsGenericProvider" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider" name="CDT User Setting Entries" prefer-non-shared="true" store-entries-with-project="true">
+				<language id="org.eclipse.cdt.core.g++">
+"""
+
+LANGUAGE_SETTINGS_TEMPLATE_DIR_HEADER = """					<resource project-relative-path="tree/@RELATIVE_PATH@">
+						<entry kind="includeFile" name="@PREINCLUDE_FILE_PATH@">
+							<flag value="LOCAL"/>
+						</entry>
+"""
+
+LANGUAGE_SETTINGS_TEMPLATE_DIR_INCLUDE = """						<entry kind="includePath" name="@INCLUDE_PATH@">
+							<flag value="LOCAL"/>
+						</entry>
+"""
+
+LANGUAGE_SETTINGS_TEMPLATE_DIR_DEFINE = """						<entry kind="macro" name="@NAME@" value=@VALUE@/>
+"""
+
+LANGUAGE_SETTINGS_TEMPLATE_DIR_FOOTER = """					</resource>
+"""
+
+LANGUAGE_SETTINGS_TEMPLATE_FOOTER = """				</language>
+			</provider>
+			<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-859273372804152468" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="@COMPILER_FLAGS@ -E -P -v -dD &quot;${INPUTS}&quot; -std=c++11" prefer-non-shared="true" store-entries-with-project="true">
+				<language-scope id="org.eclipse.cdt.core.gcc"/>
+				<language-scope id="org.eclipse.cdt.core.g++"/>
+			</provider>
+			<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+		</extension>
+	</configuration>
 </project>
 """
 
+
 GECKO_LAUNCH_CONFIG_TEMPLATE = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType">
 <booleanAttribute key="org.eclipse.cdt.dsf.gdb.AUTO_SOLIB" value="true"/>
 <listAttribute key="org.eclipse.cdt.dsf.gdb.AUTO_SOLIB_LIST"/>
 <stringAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_NAME" value="lldb"/>
 <booleanAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_ON_FORK" value="false"/>
 <stringAttribute key="org.eclipse.cdt.dsf.gdb.GDB_INIT" value=""/>
 <booleanAttribute key="org.eclipse.cdt.dsf.gdb.NON_STOP" value="false"/>