diff --git a/gyp/.flake8 b/gyp/.flake8 index 139e952e7d..ea0c7680ef 100644 --- a/gyp/.flake8 +++ b/gyp/.flake8 @@ -1,4 +1,4 @@ [flake8] -max-complexity = 10 +max-complexity = 101 max-line-length = 88 -extend-ignore = E203,C901,E501 +extend-ignore = E203 # whitespace before ':' to agree with psf/black diff --git a/gyp/.github/workflows/Python_tests.yml b/gyp/.github/workflows/Python_tests.yml index a93b92f426..128654f312 100644 --- a/gyp/.github/workflows/Python_tests.yml +++ b/gyp/.github/workflows/Python_tests.yml @@ -12,7 +12,7 @@ jobs: max-parallel: 15 matrix: os: [macos-latest, ubuntu-latest] # , windows-latest] - python-version: [2.7, 3.6, 3.7, 3.8] # 3.5, + python-version: [2.7, 3.6, 3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/gyp/.github/workflows/node-gyp.yml b/gyp/.github/workflows/node-gyp.yml new file mode 100644 index 0000000000..78fe502bda --- /dev/null +++ b/gyp/.github/workflows/node-gyp.yml @@ -0,0 +1,40 @@ +name: node-gyp integration + +on: [push, pull_request] + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Clone gyp-next + uses: actions/checkout@v2 + with: + path: gyp-next + - name: Clone nodejs/node-gyp + uses: actions/checkout@v2 + with: + repository: nodejs/node-gyp + path: node-gyp + - uses: actions/setup-node@v1 + with: + node-version: 14.x + - uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Install dependencies + run: | + cd node-gyp + npm install --no-progress + - name: Replace gyp in node-gyp + shell: bash + run: | + rm -rf node-gyp/gyp + cp -r gyp-next node-gyp/gyp + - name: Run tests + run: | + cd node-gyp + npm test diff --git a/gyp/.github/workflows/nodejs-windows.yml b/gyp/.github/workflows/nodejs-windows.yml index 48a42372c2..fffe96e33b 100644 --- a/gyp/.github/workflows/nodejs-windows.yml +++ b/gyp/.github/workflows/nodejs-windows.yml @@ -6,7 +6,7 @@ jobs: build-windows: runs-on: windows-latest steps: - - name: Clone node-gyp + - name: Clone gyp-next uses: actions/checkout@v2 with: path: gyp-next diff --git a/gyp/CHANGELOG.md b/gyp/CHANGELOG.md index 8cbcdd3b72..ea632d388f 100644 --- a/gyp/CHANGELOG.md +++ b/gyp/CHANGELOG.md @@ -6,6 +6,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +## [0.6.1] - 2020-10-14 + +### Fixed +- Correctly rename object files for absolute paths in MSVS generator. + +## [0.6.0] - 2020-10-13 + +### Added +- The Makefile generator will now output shared libraries directly to the product + directory on all platforms (previously only macOS). + +## [0.5.0] - 2020-09-30 + +### Added +- Extended compile_commands_json generator to consider more file extensions than + just `c` and `cc`. `cpp` and `cxx` are now supported. +- Source files with duplicate basenames are now supported. + +### Removed +- The `--no-duplicate-basename-check` option was removed. +- The `msvs_enable_marmasm` configuration option was removed in favor of + auto-inclusion of the "marmasm" sections for Windows on ARM. + ## [0.4.0] - 2020-07-14 ### Added @@ -34,7 +57,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). This is the first release of this project, based on https://chromium.googlesource.com/external/gyp with changes made over the years in Node.js and node-gyp. -[Unreleased]: https://github.com/nodejs/gyp-next/compare/v0.4.0...HEAD +[Unreleased]: https://github.com/nodejs/gyp-next/compare/v0.6.1...HEAD +[0.6.1]: https://github.com/nodejs/gyp-next/compare/v0.6.0...v0.6.1 +[0.6.0]: https://github.com/nodejs/gyp-next/compare/v0.5.0...v0.6.0 +[0.5.0]: https://github.com/nodejs/gyp-next/compare/v0.4.0...v0.5.0 [0.4.0]: https://github.com/nodejs/gyp-next/compare/v0.3.0...v0.4.0 [0.3.0]: https://github.com/nodejs/gyp-next/compare/v0.2.1...v0.3.0 [0.2.1]: https://github.com/nodejs/gyp-next/compare/v0.2.0...v0.2.1 diff --git a/gyp/README.md b/gyp/README.md index c0d73ac958..9ffc2b21e8 100644 --- a/gyp/README.md +++ b/gyp/README.md @@ -2,3 +2,6 @@ GYP can Generate Your Projects. =================================== Documents are available at [gyp.gsrc.io](https://gyp.gsrc.io), or you can check out ```md-pages``` branch to read those documents offline. + +__gyp-next__ is [released](https://github.com/nodejs/gyp-next/releases) to the [__Python Packaging Index__](https://pypi.org/project/gyp-next) (PyPI) and can be installed with the command: +* `python3 -m pip install gyp-next` diff --git a/gyp/pylib/gyp/MSVSSettings_test.py b/gyp/pylib/gyp/MSVSSettings_test.py index c53c88e824..99860c880e 100755 --- a/gyp/pylib/gyp/MSVSSettings_test.py +++ b/gyp/pylib/gyp/MSVSSettings_test.py @@ -678,7 +678,8 @@ def testConvertToMSBuildSettings_warnings(self): "MSBuild, index value (21) not in expected range [0, 3)", "Warning: while converting VCCLCompilerTool/UsePrecompiledHeader to " "MSBuild, index value (13) not in expected range [0, 3)", - "Warning: while converting VCCLCompilerTool/GeneratePreprocessedFile to " + "Warning: while converting " + "VCCLCompilerTool/GeneratePreprocessedFile to " "MSBuild, value must be one of [0, 1, 2]; got 14", "Warning: while converting VCLinkerTool/Driver to " "MSBuild, index value (10) not in expected range [0, 4)", @@ -1348,7 +1349,8 @@ def testConvertToMSBuildSettings_actual(self): "EmbedManifest": "false", "GenerateCatalogFiles": "true", "InputResourceManifests": "asfsfdafs", - "ManifestResourceFile": "$(IntDir)\\$(TargetFileName).embed.manifest.resfdsf", + "ManifestResourceFile": + "$(IntDir)\\$(TargetFileName).embed.manifest.resfdsf", "OutputManifestFile": "$(TargetPath).manifestdfs", "RegistrarScriptFile": "sdfsfd", "ReplacementsFile": "sdffsd", @@ -1532,7 +1534,8 @@ def testConvertToMSBuildSettings_actual(self): "LinkIncremental": "", }, "ManifestResourceCompile": { - "ResourceOutputFileName": "$(IntDir)$(TargetFileName).embed.manifest.resfdsf" + "ResourceOutputFileName": + "$(IntDir)$(TargetFileName).embed.manifest.resfdsf" }, } self.maxDiff = 9999 # on failure display a long diff diff --git a/gyp/pylib/gyp/__init__.py b/gyp/pylib/gyp/__init__.py index e249536429..f6ea625d40 100755 --- a/gyp/pylib/gyp/__init__.py +++ b/gyp/pylib/gyp/__init__.py @@ -68,7 +68,6 @@ def Load( params=None, check=False, circular_check=True, - duplicate_basename_check=True, ): """ Loads one or more specified build files. @@ -156,7 +155,6 @@ def Load( generator_input_info, check, circular_check, - duplicate_basename_check, params["parallel"], params["root_targets"], ) @@ -431,20 +429,6 @@ def gyp_main(args): regenerate=False, help="don't check for circular relationships between files", ) - # --no-duplicate-basename-check disables the check for duplicate basenames - # in a static_library/shared_library project. Visual C++ 2008 generator - # doesn't support this configuration. Libtool on Mac also generates warnings - # when duplicate basenames are passed into Make generator on Mac. - # TODO(yukawa): Remove this option when these legacy generators are - # deprecated. - parser.add_argument( - "--no-duplicate-basename-check", - dest="duplicate_basename_check", - action="store_false", - default=True, - regenerate=False, - help="don't check for duplicate basenames", - ) parser.add_argument( "--no-parallel", action="store_true", @@ -651,7 +635,6 @@ def gyp_main(args): params, options.check, options.circular_check, - options.duplicate_basename_check, ) # TODO(mark): Pass |data| for now because the generator needs a list of diff --git a/gyp/pylib/gyp/common.py b/gyp/pylib/gyp/common.py index bfe546f867..a915643867 100644 --- a/gyp/pylib/gyp/common.py +++ b/gyp/pylib/gyp/common.py @@ -352,10 +352,14 @@ class Writer(object): """Wrapper around file which only covers the target if it differs.""" def __init__(self): - # On Cygwin remove the "dir" argument because `C:` prefixed paths are treated as relative, - # consequently ending up with current dir "/cygdrive/c/..." being prefixed to those, which was - # obviously a non-existent path, for example: "/cygdrive/c//C:\". - # See https://docs.python.org/2/library/tempfile.html#tempfile.mkstemp for more details + # On Cygwin remove the "dir" argument + # `C:` prefixed paths are treated as relative, + # consequently ending up with current dir "/cygdrive/c/..." + # being prefixed to those, which was + # obviously a non-existent path, + # for example: "/cygdrive/c//C:\". + # For more details see: + # https://docs.python.org/2/library/tempfile.html#tempfile.mkstemp base_temp_dir = "" if IsCygwin() else os.path.dirname(filename) # Pick temporary file. tmp_fd, self.tmp_path = tempfile.mkstemp( @@ -391,13 +395,15 @@ def close(self): # one. os.unlink(self.tmp_path) else: - # The new file is different from the old one, or there is no old one. + # The new file is different from the old one, + # or there is no old one. # Rename the new file to the permanent name. # # tempfile.mkstemp uses an overly restrictive mode, resulting in a # file that can only be read by the owner, regardless of the umask. - # There's no reason to not respect the umask here, which means that - # an extra hoop is required to fetch it and reset the new file's mode. + # There's no reason to not respect the umask here, + # which means that an extra hoop is required + # to fetch it and reset the new file's mode. # # No way to get the umask without setting a new one? Set a safe one # and then set it back to the old value. @@ -406,8 +412,8 @@ def close(self): os.chmod(self.tmp_path, 0o666 & ~umask) if sys.platform == "win32" and os.path.exists(filename): # NOTE: on windows (but not cygwin) rename will not replace an - # existing file, so it must be preceded with a remove. Sadly there - # is no way to make the switch atomic. + # existing file, so it must be preceded with a remove. + # Sadly there is no way to make the switch atomic. os.remove(filename) os.rename(self.tmp_path, filename) except Exception: diff --git a/gyp/pylib/gyp/generator/android.py b/gyp/pylib/gyp/generator/android.py index 3ac61008b9..16728847c5 100644 --- a/gyp/pylib/gyp/generator/android.py +++ b/gyp/pylib/gyp/generator/android.py @@ -557,7 +557,7 @@ def WriteSources(self, spec, configs, extra_sources): These are source files necessary to build the current target. We need to handle shared_intermediate directory source files as a special case by copying them to the intermediate directory and - treating them as a genereated sources. Otherwise the Android build + treating them as a generated sources. Otherwise the Android build rules won't pick them up. Args: diff --git a/gyp/pylib/gyp/generator/compile_commands_json.py b/gyp/pylib/gyp/generator/compile_commands_json.py index 9bc21ff834..f330a04dea 100644 --- a/gyp/pylib/gyp/generator/compile_commands_json.py +++ b/gyp/pylib/gyp/generator/compile_commands_json.py @@ -61,8 +61,8 @@ def AddCommandsForTarget(cwd, target, params, per_config_commands): defines = ["-D" + s for s in defines] # TODO(bnoordhuis) Handle generated source files. - sources = target.get("sources", []) - sources = [s for s in sources if s.endswith(".c") or s.endswith(".cc")] + extensions = (".c", ".cc", ".cpp", ".cxx") + sources = [s for s in target.get("sources", []) if s.endswith(extensions)] def resolve(filename): return os.path.abspath(os.path.join(cwd, filename)) diff --git a/gyp/pylib/gyp/generator/make.py b/gyp/pylib/gyp/generator/make.py index 6e1c5205cf..d163ae3135 100644 --- a/gyp/pylib/gyp/generator/make.py +++ b/gyp/pylib/gyp/generator/make.py @@ -30,7 +30,6 @@ import gyp.common import gyp.xcode_emulation from gyp.common import GetEnvironFallback -from gyp.common import GypError import hashlib @@ -177,7 +176,7 @@ def CalculateGeneratorInputInfo(params): quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ cmd_solink_module = $(LINK.$(TOOLSET)) -o $@ -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) -""" +""" # noqa: E501 LINK_COMMANDS_MAC = """\ quiet_cmd_alink = LIBTOOL-STATIC $@ @@ -191,7 +190,7 @@ def CalculateGeneratorInputInfo(params): quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) -""" +""" # noqa: E501 LINK_COMMANDS_ANDROID = """\ quiet_cmd_alink = AR($(TOOLSET)) $@ @@ -218,7 +217,7 @@ def CalculateGeneratorInputInfo(params): cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) quiet_cmd_solink_module_host = SOLINK_MODULE($(TOOLSET)) $@ cmd_solink_module_host = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) -""" +""" # noqa: E501 LINK_COMMANDS_AIX = """\ @@ -236,7 +235,7 @@ def CalculateGeneratorInputInfo(params): quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) -""" +""" # noqa: E501 LINK_COMMANDS_OS390 = """\ @@ -254,8 +253,7 @@ def CalculateGeneratorInputInfo(params): quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ cmd_solink_module = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) -Wl,DLL - -""" +""" # noqa: E501 # Header of toplevel Makefile. @@ -404,7 +402,7 @@ def CalculateGeneratorInputInfo(params): cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp %(copy_archive_args)s "$<" "$@") %(link_commands)s -""" +""" # noqa: E501 r""" # Define an escape_quotes function to escape single quotes. # This allows us to handle quotes properly as long as we always use @@ -503,7 +501,7 @@ def CalculateGeneratorInputInfo(params): .PHONY: FORCE_DO_CMD FORCE_DO_CMD: -""" +""" # noqa: E501 ) SHARED_HEADER_MAC_COMMANDS = """ @@ -534,7 +532,7 @@ def CalculateGeneratorInputInfo(params): quiet_cmd_infoplist = INFOPLIST $@ cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" -""" +""" # noqa: E501 def WriteRootHeaderSuffixRules(writer): @@ -672,43 +670,6 @@ def SourceifyAndQuoteSpaces(path): return QuoteSpaces(Sourceify(path)) -# TODO: Avoid code duplication with _ValidateSourcesForMSVSProject in msvs.py. -def _ValidateSourcesForOSX(spec, all_sources): - """Makes sure if duplicate basenames are not specified in the source list. - - Arguments: - spec: The target dictionary containing the properties of the target. - """ - if spec.get("type", None) != "static_library": - return - - basenames = {} - for source in all_sources: - name, ext = os.path.splitext(source) - is_compiled_file = ext in [".c", ".cc", ".cpp", ".cxx", ".m", ".mm", ".s", ".S"] - if not is_compiled_file: - continue - basename = os.path.basename(name) # Don't include extension. - basenames.setdefault(basename, []).append(source) - - error = "" - for basename, files in basenames.items(): - if len(files) > 1: - error += " %s: %s\n" % (basename, " ".join(files)) - - if error: - print( - ( - "static library %s has several files with the same basename:\n" - % spec["target_name"] - ) - + error - + "libtool on OS X will generate" - + " warnings for them." - ) - raise GypError("Duplicate basenames in sources section, see list above") - - # Map from qualified target to path to output. target_outputs = {} # Map from qualified target to any linkable output. A subset @@ -867,10 +828,6 @@ def Write( # Sources. all_sources = spec.get("sources", []) + extra_sources if all_sources: - if self.flavor == "mac": - # libtool on OS X generates warnings for duplicate basenames in the same - # target. - _ValidateSourcesForOSX(spec, all_sources) self.WriteSources( configs, deps, @@ -1342,7 +1299,10 @@ def WriteSources( ) if self.flavor == "mac": - cflags = self.xcode_settings.GetCflags(configname, arch=config.get('xcode_configuration_platform')) + cflags = self.xcode_settings.GetCflags( + configname, + arch=config.get('xcode_configuration_platform') + ) cflags_c = self.xcode_settings.GetCflagsC(configname) cflags_cc = self.xcode_settings.GetCflagsCC(configname) cflags_objc = self.xcode_settings.GetCflagsObjC(configname) @@ -1659,12 +1619,10 @@ def WriteTarget( ldflags = config.get("ldflags", []) # Compute an rpath for this output if needed. if any(dep.endswith(".so") or ".so." in dep for dep in deps): - # We want to get the literal string "$ORIGIN" into the link command, - # so we need lots of escaping. - ldflags.append(r"-Wl,-rpath=\$$ORIGIN/lib.%s/" % self.toolset) - ldflags.append( - r"-Wl,-rpath-link=\$(builddir)/lib.%s/" % self.toolset - ) + # We want to get the literal string "$ORIGIN" + # into the link command, so we need lots of escaping. + ldflags.append(r"-Wl,-rpath=\$$ORIGIN/") + ldflags.append(r"-Wl,-rpath-link=\$(builddir)/") library_dirs = config.get("library_dirs", []) ldflags += [("-L%s" % library_dir) for library_dir in library_dirs] self.WriteList(ldflags, "LDFLAGS_%s" % configname) @@ -2212,14 +2170,16 @@ def ExpandInputRoot(self, template, expansion, dirname): def _InstallableTargetInstallPath(self): """Returns the location of the final output for an installable target.""" + # Functionality removed for all platforms to match Xcode and hoist + # shared libraries into PRODUCT_DIR for users: # Xcode puts shared_library results into PRODUCT_DIR, and some gyp files # rely on this. Emulate this behavior for mac. - if self.type == "shared_library" and ( - self.flavor != "mac" or self.toolset != "target" - ): - # Install all shared libs into a common directory (per toolset) for - # convenient access with LD_LIBRARY_PATH. - return "$(builddir)/lib.%s/%s" % (self.toolset, self.alias) + # if self.type == "shared_library" and ( + # self.flavor != "mac" or self.toolset != "target" + # ): + # # Install all shared libs into a common directory (per toolset) for + # # convenient access with LD_LIBRARY_PATH. + # return "$(builddir)/lib.%s/%s" % (self.toolset, self.alias) return "$(builddir)/" + self.alias diff --git a/gyp/pylib/gyp/generator/msvs.py b/gyp/pylib/gyp/generator/msvs.py index 5bfceb05cb..e05a8a78a9 100644 --- a/gyp/pylib/gyp/generator/msvs.py +++ b/gyp/pylib/gyp/generator/msvs.py @@ -84,7 +84,6 @@ "msvs_enable_winrt", "msvs_requires_importlibrary", "msvs_enable_winphone", - "msvs_enable_marmasm", "msvs_application_type_revision", "msvs_target_platform_version", "msvs_target_platform_minversion", @@ -183,7 +182,8 @@ def _FixPath(path): def _IsWindowsAbsPath(path): """ - On Cygwin systems Python needs a little help determining if a path is an absolute Windows path or not, so that + On Cygwin systems Python needs a little help determining if a path + is an absolute Windows path or not, so that it does not treat those as relative, which results in bad paths like: '..\\C:\\\\some_source_code_file.cc' """ @@ -753,7 +753,7 @@ def _EscapeEnvironmentVariableExpansion(s): Returns: The escaped string. - """ + """ # noqa: E731,E123,E501 s = s.replace("%", "%%") return s @@ -846,7 +846,7 @@ def _EscapeCppDefineForMSVS(s): s = _EscapeEnvironmentVariableExpansion(s) s = _EscapeCommandLineArgumentForMSVS(s) s = _EscapeVCProjCommandLineArgListItem(s) - # cl.exe replaces literal # characters with = in preprocesor definitions for + # cl.exe replaces literal # characters with = in preprocessor definitions for # some reason. Octal-encode to work around that. s = s.replace("#", "\\%03o" % ord("#")) return s @@ -885,7 +885,7 @@ def _EscapeCppDefineForMSBuild(s): s = _EscapeEnvironmentVariableExpansion(s) s = _EscapeCommandLineArgumentForMSBuild(s) s = _EscapeMSBuildSpecialCharacters(s) - # cl.exe replaces literal # characters with = in preprocesor definitions for + # cl.exe replaces literal # characters with = in preprocessor definitions for # some reason. Octal-encode to work around that. s = s.replace("#", "\\%03o" % ord("#")) return s @@ -1029,45 +1029,6 @@ def _GenerateProject(project, options, version, generator_flags, spec): return _GenerateMSVSProject(project, options, version, generator_flags) -# TODO: Avoid code duplication with _ValidateSourcesForOSX in make.py. -def _ValidateSourcesForMSVSProject(spec, version): - """Makes sure if duplicate basenames are not specified in the source list. - - Arguments: - spec: The target dictionary containing the properties of the target. - version: The VisualStudioVersion object. - """ - # This validation should not be applied to MSVC2010 and later. - assert not version.UsesVcxproj() - - # TODO: Check if MSVC allows this for loadable_module targets. - if spec.get("type", None) not in ("static_library", "shared_library"): - return - sources = spec.get("sources", []) - basenames = {} - for source in sources: - name, ext = os.path.splitext(source) - is_compiled_file = ext in [".c", ".cc", ".cpp", ".cxx", ".m", ".mm", ".s", ".S"] - if not is_compiled_file: - continue - basename = os.path.basename(name) # Don't include extension. - basenames.setdefault(basename, []).append(source) - - error = "" - for basename, files in basenames.items(): - if len(files) > 1: - error += " %s: %s\n" % (basename, " ".join(files)) - - if error: - print( - "static library %s has several files with the same basename:\n" - % spec["target_name"] - + error - + "MSVC08 cannot handle that." - ) - raise GypError("Duplicate basenames in sources section, see list above") - - def _GenerateMSVSProject(project, options, version, generator_flags): """Generates a .vcproj file. It may create .rules and .user files too. @@ -1094,11 +1055,6 @@ def _GenerateMSVSProject(project, options, version, generator_flags): for config_name, config in spec["configurations"].items(): _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config) - # MSVC08 and prior version cannot handle duplicate basenames in the same - # target. - # TODO: Take excluded sources into consideration if possible. - _ValidateSourcesForMSVSProject(spec, version) - # Prepare list of sources and excluded sources. gyp_file = os.path.split(project.build_file)[1] sources, excluded_sources = _PrepareListOfSources(spec, generator_flags, gyp_file) @@ -1415,7 +1371,7 @@ def _GetOutputTargetExt(spec): def _GetDefines(config): - """Returns the list of preprocessor definitions for this configuation. + """Returns the list of preprocessor definitions for this configuration. Arguments: config: The dictionary that defines the special processing to be done @@ -2277,7 +2233,7 @@ def _AppendFiltersForMSBuild( sources: The hierarchy of filters and sources to process. extension_to_rule_name: A dictionary mapping file extensions to rules. filter_group: The list to which filter entries will be appended. - source_group: The list to which source entries will be appeneded. + source_group: The list to which source entries will be appended. """ for source in sources: if isinstance(source, MSVSProject.Filter): @@ -2374,8 +2330,8 @@ def _GenerateRulesForMSBuild( ): # MSBuild rules are implemented using three files: an XML file, a .targets # file and a .props file. - # See http://blogs.msdn.com/b/vcblog/archive/2010/04/21/quick-help-on-vs2010-custom-build-rule.aspx - # for more details. + # For more details see: + # https://devblogs.microsoft.com/cppblog/quick-help-on-vs2010-custom-build-rule/ rules = spec.get("rules", []) rules_native = [r for r in rules if not int(r.get("msvs_external_rule", 0))] rules_external = [r for r in rules if int(r.get("msvs_external_rule", 0))] @@ -3623,8 +3579,9 @@ def _AddSources2( if precompiled_source != "": precompiled_source = _FixPath(precompiled_source) if not extensions_excluded_from_precompile: - # If the precompiled header is generated by a C source, we must - # not try to use it for C++ sources, and vice versa. + # If the precompiled header is generated by a C source, + # we must not try to use it for C++ sources, + # and vice versa. basename, extension = os.path.splitext(precompiled_source) if extension == ".c": extensions_excluded_from_precompile = [ @@ -3657,6 +3614,17 @@ def _AddSources2( extension_to_rule_name, _GetUniquePlatforms(spec), ) + if group == "compile": + # Always add an value to support duplicate + # source file basenames. + file_name = os.path.splitext(source)[0] + ".obj" + if os.path.isabs(file_name): + file_name = os.path.splitdrive(file_name)[1] + elif file_name.startswith("..\\"): + file_name = re.sub(r"^(\.\.\\)+", "", file_name) + elif file_name.startswith("$("): + file_name = re.sub(r"^\$\([^)]+\)\\", "", file_name) + detail.append(["ObjectFileName", "$(IntDir)\\" + file_name]) grouped_sources[group].append([element, {"Include": source}] + detail) @@ -3704,6 +3672,7 @@ def _GetMSBuildProjectReferences(project): def _GenerateMSBuildProject(project, options, version, generator_flags, spec): spec = project.spec configurations = spec["configurations"] + toolset = spec["toolset"] project_dir, project_file_name = os.path.split(project.path) gyp.common.EnsureDirExists(project.path) # Prepare list of sources and excluded sources. @@ -3717,6 +3686,7 @@ def _GenerateMSBuildProject(project, options, version, generator_flags, spec): rule_dependencies = set() extension_to_rule_name = {} list_excluded = generator_flags.get("msvs_list_excluded_files", True) + platforms = _GetUniquePlatforms(spec) # Don't generate rules if we are using an external builder like ninja. if not spec.get("msvs_external_builder"): @@ -3759,7 +3729,7 @@ def _GenerateMSBuildProject(project, options, version, generator_flags, spec): sources, rule_dependencies, extension_to_rule_name, - _GetUniquePlatforms(spec), + platforms, ) missing_sources = _VerifySourcesExist(sources, project_dir) @@ -3812,7 +3782,7 @@ def _GenerateMSBuildProject(project, options, version, generator_flags, spec): content += _GetMSBuildLocalProperties(project.msbuild_toolset) content += import_cpp_props_section content += import_masm_props_section - if spec.get("msvs_enable_marmasm"): + if "arm64" in platforms and toolset == "target": content += import_marmasm_props_section content += _GetMSBuildExtensions(props_files_of_rules) content += _GetMSBuildPropertySheets(configurations, spec) @@ -3834,7 +3804,7 @@ def _GenerateMSBuildProject(project, options, version, generator_flags, spec): content += _GetMSBuildProjectReferences(project) content += import_cpp_targets_section content += import_masm_targets_section - if spec.get("msvs_enable_marmasm"): + if "arm64" in platforms and toolset == "target": content += import_marmasm_targets_section content += _GetMSBuildExtensionTargets(targets_files_of_rules) diff --git a/gyp/pylib/gyp/generator/ninja.py b/gyp/pylib/gyp/generator/ninja.py index 384b252e73..e064bad7ed 100644 --- a/gyp/pylib/gyp/generator/ninja.py +++ b/gyp/pylib/gyp/generator/ninja.py @@ -90,7 +90,7 @@ def Define(d, flavor): """Takes a preprocessor define and returns a -D parameter that's ninja- and shell-escaped.""" if flavor == "win": - # cl.exe replaces literal # characters with = in preprocesor definitions for + # cl.exe replaces literal # characters with = in preprocessor definitions for # some reason. Octal-encode to work around that. d = d.replace("#", "\\%03o" % ord("#")) return QuoteShellArgument(ninja_syntax.escape("-D" + d), flavor) @@ -781,9 +781,10 @@ def cygwin_munge(path): rule.get("process_outputs_as_mac_bundle_resources", False) ): extra_mac_bundle_resources += outputs - # Note: This is n_resources * n_outputs_in_rule. Put to-be-removed - # items in a set and remove them all in a single pass if this becomes - # a performance issue. + # Note: This is n_resources * n_outputs_in_rule. + # Put to-be-removed items in a set and + # remove them all in a single pass + # if this becomes a performance issue. if was_mac_bundle_resource: mac_bundle_resources.remove(source) @@ -816,7 +817,7 @@ def cygwin_munge(path): outputs = [self.GypPathToNinja(o, env) for o in outputs] if self.flavor == "win": - # WriteNewNinjaRule uses unique_name for creating an rsp file on win. + # WriteNewNinjaRule uses unique_name to create a rsp file on win. extra_bindings.append( ("unique_name", hashlib.md5(outputs[0]).hexdigest()) ) @@ -853,11 +854,12 @@ def WriteCopies(self, copies, prebuild, mac_bundle_depends): outputs += self.ninja.build(dst, "copy", src, order_only=prebuild) if self.is_mac_bundle: # gyp has mac_bundle_resources to copy things into a bundle's - # Resources folder, but there's no built-in way to copy files to other - # places in the bundle. Hence, some targets use copies for this. Check - # if this file is copied into the current bundle, and if so add it to - # the bundle depends so that dependent targets get rebuilt if the copy - # input changes. + # Resources folder, but there's no built-in way to copy files + # to other places in the bundle. + # Hence, some targets use copies for this. + # Check if this file is copied into the current bundle, + # and if so add it to the bundle depends so + # that dependent targets get rebuilt if the copy input changes. if dst.startswith( self.xcode_settings.GetBundleContentsFolderPath() ): @@ -1513,8 +1515,8 @@ def WriteLinkForArch( if self.flavor != "win": link_file_list = output if self.is_mac_bundle: - # 'Dependency Framework.framework/Versions/A/Dependency Framework' -> - # 'Dependency Framework.framework.rsp' + # 'Dependency Framework.framework/Versions/A/Dependency Framework' + # -> 'Dependency Framework.framework.rsp' link_file_list = self.xcode_settings.GetWrapperName() if arch: link_file_list += "." + arch @@ -1628,7 +1630,8 @@ def WriteTarget(self, spec, config_name, config, link_deps, compile_deps): variables=variables, ) inputs.append(output) - # TODO: It's not clear if libtool_flags should be passed to the alink + # TODO: It's not clear if + # libtool_flags should be passed to the alink # call that combines single-arch .a files into a fat .a file. self.AppendPostbuildVariable( variables, spec, self.target.binary, self.target.binary @@ -2535,9 +2538,10 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params, config_name "solink", description="SOLINK $lib", restat=True, - command=mtime_preserving_solink_base % {"suffix": "@$link_file_list"}, + command=mtime_preserving_solink_base % {"suffix": "@$link_file_list"}, # noqa: E501 rspfile="$link_file_list", - rspfile_content="-Wl,--whole-archive $in $solibs -Wl,--no-whole-archive $libs", + rspfile_content=("-Wl,--whole-archive $in $solibs -Wl," + "--no-whole-archive $libs"), pool="link_pool", ) master_ninja.rule( diff --git a/gyp/pylib/gyp/generator/xcode.py b/gyp/pylib/gyp/generator/xcode.py index 535c5400ce..9e7e99e9e1 100644 --- a/gyp/pylib/gyp/generator/xcode.py +++ b/gyp/pylib/gyp/generator/xcode.py @@ -594,7 +594,7 @@ def ExpandXcodeVariables(string, expansions): def EscapeXcodeDefine(s): """We must escape the defines that we give to XCode so that it knows not to split on spaces and to respect backslash and quote literals. However, we - must not quote the define, or Xcode will incorrectly intepret variables + must not quote the define, or Xcode will incorrectly interpret variables especially $(inherited).""" return re.sub(_xcode_define_re, r"\\\1", s) @@ -735,7 +735,8 @@ def GenerateOutput(target_list, target_dicts, data, params): "loadable_module+xcuitest": "com.apple.product-type.bundle.ui-testing", "shared_library+bundle": "com.apple.product-type.framework", "executable+extension+bundle": "com.apple.product-type.app-extension", - "executable+watch+extension+bundle": "com.apple.product-type.watchkit-extension", + "executable+watch+extension+bundle": + "com.apple.product-type.watchkit-extension", "executable+watch+bundle": "com.apple.product-type.application.watchapp", "mac_kernel_extension+bundle": "com.apple.product-type.kernel-extension", } @@ -1026,7 +1027,7 @@ def GenerateOutput(target_list, target_dicts, data, params): for output in rule.get("outputs", []): # Fortunately, Xcode and make both use $(VAR) format for their # variables, so the expansion is the only transformation necessary. - # Any remaning $(VAR)-type variables in the string can be given + # Any remaining $(VAR)-type variables in the string can be given # directly to make, which will pick up the correct settings from # what Xcode puts into the environment. concrete_output = ExpandXcodeVariables(output, rule_input_dict) @@ -1151,8 +1152,8 @@ def GenerateOutput(target_list, target_dicts, data, params): '\t@mkdir -p "%s"\n' % '" "'.join(concrete_output_dirs) ) - # The rule message and action have already had the necessary variable - # substitutions performed. + # The rule message and action have already had + # the necessary variable substitutions performed. if message: # Mark it with note: so Xcode picks it up in build output. makefile.write("\t@echo note: %s\n" % message) @@ -1204,8 +1205,8 @@ def GenerateOutput(target_list, target_dicts, data, params): support_xct.AppendProperty("buildPhases", ssbp) else: # TODO(mark): this assumes too much knowledge of the internals of - # xcodeproj_file; some of these smarts should move into xcodeproj_file - # itself. + # xcodeproj_file; some of these smarts should move + # into xcodeproj_file itself. xct._properties["buildPhases"].insert(prebuild_index, ssbp) prebuild_index = prebuild_index + 1 diff --git a/gyp/pylib/gyp/input.py b/gyp/pylib/gyp/input.py index 00c4ee1f96..5504390c0b 100644 --- a/gyp/pylib/gyp/input.py +++ b/gyp/pylib/gyp/input.py @@ -66,7 +66,7 @@ def IsPathSection(section): if section in path_sections: return True - # Sections mathing the regexp '_(dir|file|path)s?$' are also + # Sections matching the regexp '_(dir|file|path)s?$' are also # considered PathSections. Using manual string matching since that # is much faster than the regexp and this can be called hundreds of # thousands of times so micro performance matters. @@ -232,8 +232,8 @@ def LoadOneBuildFile(build_file_path, data, aux_data, includes, is_target, check # to make sure platform specific newlines ('\r\n' or '\r') are converted to '\n' # which otherwise will fail eval() if sys.platform == "zos": - # On z/OS, universal-newlines mode treats the file as an ascii file. But since - # node-gyp produces ebcdic files, do not use that mode. + # On z/OS, universal-newlines mode treats the file as an ascii file. + # But since node-gyp produces ebcdic files, do not use that mode. build_file_contents = open(build_file_path, "r").read() else: build_file_contents = open(build_file_path, "rU").read() @@ -1731,10 +1731,10 @@ def ExtractNodeRef(node): node_dependent.dependencies, key=ExtractNodeRef ): if node_dependent_dependency.ref not in flat_list: - # The dependent one or more dependencies not in flat_list. There - # will be more chances to add it to flat_list when examining - # it again as a dependent of those other dependencies, provided - # that there are no cycles. + # The dependent one or more dependencies not in flat_list. + # There will be more chances to add it to flat_list + # when examining it again as a dependent of those other + # dependencies, provided that there are no cycles. is_in_degree_zero = False break @@ -2427,7 +2427,7 @@ def MergeDicts(to, fro, to_file, fro_file): def MergeConfigWithInheritance( new_configuration_dict, build_file, target_dict, configuration, visited ): - # Skip if previously visted. + # Skip if previously visited. if configuration in visited: return @@ -2641,10 +2641,10 @@ def ProcessListFiltersInDict(name, the_dict): pattern_re = re.compile(pattern) if action == "exclude": - # This item matches an exclude regex, so set its value to 0 (exclude). + # This item matches an exclude regex, set its value to 0 (exclude). action_value = 0 elif action == "include": - # This item matches an include regex, so set its value to 1 (include). + # This item matches an include regex, set its value to 1 (include). action_value = 1 else: # This is an action that doesn't make any sense. @@ -2659,8 +2659,8 @@ def ProcessListFiltersInDict(name, the_dict): for index, list_item in enumerate(the_list): if list_actions[index] == action_value: - # Even if the regex matches, nothing will change so continue (regex - # searches are expensive). + # Even if the regex matches, nothing will change so continue + # (regex searches are expensive). continue if pattern_re.search(list_item): # Regular expression match. @@ -2750,36 +2750,6 @@ def ValidateTargetType(target, target_dict): ) -def ValidateSourcesInTarget(target, target_dict, build_file, duplicate_basename_check): - if not duplicate_basename_check: - return - if target_dict.get("type", None) != "static_library": - return - sources = target_dict.get("sources", []) - basenames = {} - for source in sources: - name, ext = os.path.splitext(source) - is_compiled_file = ext in [".c", ".cc", ".cpp", ".cxx", ".m", ".mm", ".s", ".S"] - if not is_compiled_file: - continue - basename = os.path.basename(name) # Don't include extension. - basenames.setdefault(basename, []).append(source) - - error = "" - for basename, files in basenames.items(): - if len(files) > 1: - error += " %s: %s\n" % (basename, " ".join(files)) - - if error: - print( - "static library %s has several files with the same basename:\n" % target - + error - + "libtool on Mac cannot handle that. Use " - "--no-duplicate-basename-check to disable this validation." - ) - raise GypError("Duplicate basenames in sources section, see list above") - - def ValidateRulesInTarget(target, target_dict, extra_sources_for_rules): """Ensures that the rules sections in target_dict are valid and consistent, and determines which sources they apply to. @@ -3021,7 +2991,6 @@ def Load( generator_input_info, check, circular_check, - duplicate_basename_check, parallel, root_targets, ): @@ -3167,9 +3136,6 @@ def Load( target_dict = targets[target] build_file = gyp.common.BuildFile(target) ValidateTargetType(target, target_dict) - ValidateSourcesInTarget( - target, target_dict, build_file, duplicate_basename_check - ) ValidateRulesInTarget(target, target_dict, extra_sources_for_rules) ValidateRunAsInTarget(target, target_dict, build_file) ValidateActionsInTarget(target, target_dict, build_file) diff --git a/gyp/pylib/gyp/msvs_emulation.py b/gyp/pylib/gyp/msvs_emulation.py index c665c9bf90..1afc1d687e 100644 --- a/gyp/pylib/gyp/msvs_emulation.py +++ b/gyp/pylib/gyp/msvs_emulation.py @@ -814,8 +814,8 @@ def _GetLdManifestFlags( manifest_files = [] generated_manifest_outer = ( "" - "%s" - "" + "" + "%s" ) if enable_uac == "true": execution_level = self._Setting( diff --git a/gyp/pylib/gyp/xcode_emulation.py b/gyp/pylib/gyp/xcode_emulation.py index 42a4ce47ed..8af2b39f9a 100644 --- a/gyp/pylib/gyp/xcode_emulation.py +++ b/gyp/pylib/gyp/xcode_emulation.py @@ -113,7 +113,7 @@ def GetXcodeArchsDefault(): of $(ARCHS_STANDARD_INCLUDING_64_BIT) from Xcode 5.0. From Xcode 5.1, they are also part of $(ARCHS_STANDARD). - All thoses rules are coded in the construction of the |XcodeArchsDefault| + All these rules are coded in the construction of the |XcodeArchsDefault| object to use depending on the version of Xcode detected. The object is for performance reason.""" global XCODE_ARCHS_DEFAULT_CACHE @@ -1528,7 +1528,9 @@ def CLTVersion(): # volume: / # location: / # install-time: 1382544035 - # groups: com.apple.FindSystemFiles.pkg-group com.apple.DevToolsBoth.pkg-group com.apple.DevToolsNonRelocatableShared.pkg-group + # groups: com.apple.FindSystemFiles.pkg-group + # com.apple.DevToolsBoth.pkg-group + # com.apple.DevToolsNonRelocatableShared.pkg-group STANDALONE_PKG_ID = "com.apple.pkg.DeveloperToolsCLILeo" FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI" MAVERICKS_PKG_ID = "com.apple.pkg.CLTools_Executables" @@ -1732,7 +1734,8 @@ def _GetXcodeEnv( "BUILT_PRODUCTS_DIR": built_products_dir, "CONFIGURATION": configuration, "PRODUCT_NAME": xcode_settings.GetProductName(), - # See /Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX\ Product\ Types.xcspec for FULL_PRODUCT_NAME + # For FULL_PRODUCT_NAME see: + # /Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications/MacOSX\ Product\ Types.xcspec # noqa: E501 "SRCROOT": srcroot, "SOURCE_ROOT": "${SRCROOT}", # This is not true for static libraries, but currently the env is only diff --git a/gyp/pylib/gyp/xcodeproj_file.py b/gyp/pylib/gyp/xcodeproj_file.py index cde4f055f9..d90dd99dcc 100644 --- a/gyp/pylib/gyp/xcodeproj_file.py +++ b/gyp/pylib/gyp/xcodeproj_file.py @@ -515,7 +515,7 @@ def PBXProjectAncestor(self): return None def _EncodeComment(self, comment): - """Encodes a comment to be placed in the project file output, mimicing + """Encodes a comment to be placed in the project file output, mimicking Xcode behavior. """ @@ -543,7 +543,7 @@ def _EncodeTransform(self, match): return self._encode_transforms[ord(char)] def _EncodeString(self, value): - """Encodes a string to be placed in the project file output, mimicing + """Encodes a string to be placed in the project file output, mimicking Xcode behavior. """ @@ -586,7 +586,7 @@ def _XCPrint(self, file, tabs, line): def _XCPrintableValue(self, tabs, value, flatten_list=False): """Returns a representation of value that may be printed in a project file, - mimicing Xcode's behavior. + mimicking Xcode's behavior. _XCPrintableValue can handle str and int values, XCObjects (which are made printable by returning their id property), and list and dict objects @@ -831,8 +831,8 @@ def UpdateProperties(self, properties, do_copy=False): self._properties[property] = value elif isinstance(value, list): if is_strong: - # If is_strong is True, each element is an XCObject, so it's safe - # to call Copy. + # If is_strong is True, each element is an XCObject, + # so it's safe to call Copy. self._properties[property] = [] for item in value: self._properties[property].append(item.Copy()) @@ -2132,9 +2132,10 @@ def SetDestination(self, path): # to the target. Xcode uses the dstSubfolderSpec value set here # to determine the full path. # - # An alternative of xcode_emulation.py setting the values to absolute - # paths when exporting these variables has been ruled out because - # then the values would be different depending on the build tool. + # An alternative of xcode_emulation.py setting the values to + # absolute paths when exporting these variables has been + # ruled out because then the values would be different + # depending on the build tool. # # Another alternative is to invent new names for the variables used # to match to the subfolder indices in the second table. .gyp files @@ -2146,7 +2147,8 @@ def SetDestination(self, path): # Requiring prepending BUILT_PRODUCTS_DIR has been chosen because # this same way could be used to specify destinations in .gyp files # that pre-date this addition to GYP. However they would only work - # with the Xcode generator. The previous version of xcode_emulation.py + # with the Xcode generator. + # The previous version of xcode_emulation.py # does not export these variables. Such files will get the benefit # of the Xcode UI showing the proper destination name simply by # regenerating the projects with this version of GYP. diff --git a/gyp/setup.py b/gyp/setup.py index 0f75a99b18..befcdb22b5 100755 --- a/gyp/setup.py +++ b/gyp/setup.py @@ -15,7 +15,7 @@ setup( name="gyp-next", - version="0.4.0", + version="0.6.1", description="A fork of the GYP build system for use in the Node.js projects", long_description=long_description, long_description_content_type="text/markdown", diff --git a/gyp/tools/pretty_vcproj.py b/gyp/tools/pretty_vcproj.py index 38fbf3fecf..b171fae6cf 100755 --- a/gyp/tools/pretty_vcproj.py +++ b/gyp/tools/pretty_vcproj.py @@ -161,7 +161,7 @@ def CleanupVcproj(node): AbsoluteNode(sub_node) CleanupVcproj(sub_node) - # Normalize the node, and remove all extranous whitespaces. + # Normalize the node, and remove all extraneous whitespaces. for sub_node in node.childNodes: if sub_node.nodeType == Node.TEXT_NODE: sub_node.data = sub_node.data.replace("\r", "")