def enableClcache(the_compiler, env, source_dir): importFromInlineCopy("atomicwrites", must_exist=True) importFromInlineCopy("clcache", must_exist=True) cl_binary = getExecutablePath(the_compiler, env) # The compiler is passed via environment. setEnvironmentVariable(env, "CLCACHE_CL", cl_binary) env["CXX"] = env["CC"] = "<clcache>" setEnvironmentVariable(env, "CLCACHE_HIDE_OUTPUTS", "1") # The clcache stats filename needs absolute path, otherwise it will not work. clcache_stats_filename = os.path.abspath( os.path.join(source_dir, "clcache-stats.%d.txt" % os.getpid())) setEnvironmentVariable(env, "CLCACHE_STATS", clcache_stats_filename) env["CLCACHE_STATS"] = clcache_stats_filename # Unless asked to do otherwise, store ccache files in our own directory. if "CLCACHE_DIR" not in os.environ: clcache_dir = os.path.join(getCacheDir(), "clcache") makePath(clcache_dir) clcache_dir = getExternalUsePath(clcache_dir) setEnvironmentVariable(env, "CLCACHE_DIR", clcache_dir) env["CLCACHE_DIR"] = clcache_dir scons_details_logger.info( "Using inline copy of clcache with %r cl binary." % cl_binary) # Do not consider scons cache anymore. return True
def enableClcache(the_compiler, env, source_dir): importFromInlineCopy("atomicwrites", must_exist=True) importFromInlineCopy("clcache", must_exist=True) # Avoid importing this in threads, triggers CPython 3.9 importing bugs at least, # do it now, so it's not a race issue. import concurrent.futures.thread # pylint: disable=I0021,unused-import,unused-variable cl_binary = getExecutablePath(the_compiler, env) # The compiler is passed via environment. setEnvironmentVariable(env, "CLCACHE_CL", cl_binary) env["CXX"] = env["CC"] = "<clcache>" setEnvironmentVariable(env, "CLCACHE_HIDE_OUTPUTS", "1") # The clcache stats filename needs absolute path, otherwise it will not work. clcache_stats_filename = os.path.abspath( os.path.join(source_dir, "clcache-stats.%d.txt" % os.getpid()) ) setEnvironmentVariable(env, "CLCACHE_STATS", clcache_stats_filename) env["CLCACHE_STATS"] = clcache_stats_filename # Unless asked to do otherwise, store ccache files in our own directory. if "CLCACHE_DIR" not in os.environ: clcache_dir = os.path.join(getCacheDir(), "clcache") makePath(clcache_dir) clcache_dir = getExternalUsePath(clcache_dir) setEnvironmentVariable(env, "CLCACHE_DIR", clcache_dir) env["CLCACHE_DIR"] = clcache_dir scons_details_logger.info( "Using inline copy of clcache with %r cl binary." % cl_binary )
def myDetectVersion(env, cc): """Return the version of the GNU compiler, or None if it is not a GNU compiler.""" cc = env.subst(cc) if not cc: return None if "++" in os.path.basename(cc): return None version = None clvar = tuple(SCons.Util.CLVar(cc)) if clvar in v_cache: return v_cache[clvar] clvar0 = os.path.basename(clvar[0]) if isGccName(clvar0) or "clang" in clvar0: command = list(clvar) + ["-dumpversion"] else: command = list(clvar) + ["--version"] # pipe = SCons.Action._subproc(env, SCons.Util.CLVar(cc) + ['-dumpversion'], pipe = SCons.Action._subproc( # pylint: disable=protected-access env, command, stdin="devnull", stderr="devnull", stdout=subprocess.PIPE ) line = pipe.stdout.readline() # Non-GNU compiler's output (like AIX xlc's) may exceed the stdout buffer: # So continue with reading to let the child process actually terminate. while pipe.stdout.readline(): pass ret = pipe.wait() if ret != 0: return None if str is not bytes and type(line) is bytes: line = decodeData(line) line = line.strip() match = re.findall(r"[0-9]+(?:\.[0-9]+)+", line) if match: version = match[0] else: # gcc 8 or higher version = line.strip() version = tuple(int(part) for part in version.split(".")) scons_details_logger.info( "CC %r version check gives %r from %r" % (cc, version, line) ) v_cache[clvar] = version return version
def myDetectVersion(env, cc): """Return the version of the GNU compiler, or None if it is not a GNU compiler.""" cc = env.subst(cc) if not cc: return None if "++" in os.path.basename(cc): return None # Make path absolute, to improve cache hit rate. cc = getExecutablePath(cc, env) if cc is None: return None if cc not in v_cache: v_cache[cc] = _myDetectVersion(env, (cc,)) scons_details_logger.info("CC %r version check gives %r" % (cc, v_cache[cc])) return v_cache[cc]
def _myDetectVersion(env, clvar): clvar0 = os.path.basename(clvar[0]) if isGccName(clvar0) or "clang" in clvar0: command = clvar + ("-dumpversion", ) else: command = clvar + ("--version", ) # pipe = SCons.Action._subproc(env, SCons.Util.CLVar(cc) + ['-dumpversion'], pipe = SCons.Action._subproc( # pylint: disable=protected-access env, command, stdin="devnull", stderr="devnull", stdout=subprocess.PIPE) line = pipe.stdout.readline() # Non-GNU compiler's output (like AIX xlc's) may exceed the stdout buffer: # So continue with reading to let the child process actually terminate. while pipe.stdout.readline(): pass ret = pipe.wait() if ret != 0: scons_details_logger.info("Error, error exit from %r (%d) gave %r." % (command, ret, pipe.stderr.read())) return None if str is not bytes and type(line) is bytes: line = decodeData(line) line = line.strip() match = re.findall(r"[0-9]+(?:\.[0-9]+)+", line) if match: version = match[0] else: # gcc 8 or higher version = line.strip() version = tuple(int(part) for part in version.split(".")) return version
def enableCcache( the_compiler, env, source_dir, python_prefix, assume_yes_for_downloads, ): # The ccache needs absolute path, otherwise it will not work. ccache_logfile = os.path.abspath( os.path.join(source_dir, "ccache-%d.txt" % os.getpid()) ) setEnvironmentVariable(env, "CCACHE_LOGFILE", ccache_logfile) env["CCACHE_LOGFILE"] = ccache_logfile # Unless asked to do otherwise, store ccache files in our own directory. if "CCACHE_DIR" not in os.environ: ccache_dir = os.path.join(getCacheDir(), "ccache") makePath(ccache_dir) ccache_dir = getExternalUsePath(ccache_dir) setEnvironmentVariable(env, "CCACHE_DIR", ccache_dir) env["CCACHE_DIR"] = ccache_dir # First check if it's not already supposed to be a ccache, then do nothing. cc_path = getExecutablePath(the_compiler, env=env) cc_is_link, cc_link_path = getLinkTarget(cc_path) if cc_is_link and os.path.basename(cc_link_path) == "ccache": scons_details_logger.info( "Chosen compiler %s is pointing to ccache %s already." % (cc_path, cc_link_path) ) return True return _injectCcache( the_compiler=the_compiler, cc_path=cc_path, env=env, python_prefix=python_prefix, assume_yes_for_downloads=assume_yes_for_downloads, )
def _detectWindowsSDK(env): # Check if there is a WindowsSDK installed. if env.msvc_mode or env.clangcl_mode: if "WindowsSDKVersion" not in env: if "WindowsSDKVersion" in os.environ: windows_sdk_version = os.environ["WindowsSDKVersion"].rstrip( "\\") else: windows_sdk_version = None else: windows_sdk_version = env["WindowsSDKVersion"] if not windows_sdk_version: scons_logger.sysexit( "Error, the Windows SDK must be installed in Visual Studio.") scons_details_logger.info("Using Windows SDK '%s'." % windows_sdk_version) env.windows_sdk_version = tuple( int(x) for x in windows_sdk_version.split("."))
def addClangClPathFromMSVC(env, target_arch): cl_exe = getExecutablePath("cl", env=env) if cl_exe is None: scons_logger.sysexit( "Error, Visual Studio required for using ClangCL on Windows.") clang_dir = cl_exe = os.path.join(cl_exe[:cl_exe.lower().rfind("msvc")], "Llvm") if target_arch == "x86_64": clang_dir = os.path.join(clang_dir, "x64", "bin") else: clang_dir = os.path.join(clang_dir, "bin") if os.path.exists(clang_dir): scons_details_logger.info( "Adding MSVC directory %r for Clang to PATH." % clang_dir) addToPATH(env, clang_dir, prefix=True) else: scons_details_logger.info("No Clang component for MSVC found." % clang_dir)
def _enableC11Settings(env): """Decide if C11 mode can be used and enable the C compile flags for it. Args: env - scons environment with compiler information Returns: bool - c11_mode flag """ if env.clangcl_mode: c11_mode = True elif env.msvc_mode: # TODO: Make this experimental mode the default. c11_mode = (env.windows_sdk_version >= (10, 0, 19041, 0) and "msvc_c11" in env.experimental_flags) elif env.clang_mode: c11_mode = True elif env.gcc_mode and env.gcc_version >= (5, ): c11_mode = True else: c11_mode = False if c11_mode: if env.gcc_mode: env.Append(CCFLAGS=["-std=c11"]) elif env.msvc_mode: env.Append(CCFLAGS=["/std:c11"]) if env.msvc_mode and c11_mode: # Windows SDK shows this even in non-debug mode in C11 mode. env.Append(CCFLAGS=["/wd5105"]) scons_details_logger.info("Using C11 mode: %s" % c11_mode) env.c11_mode = c11_mode
def addClangClPathFromMSVC(env): cl_exe = getExecutablePath("cl", env=env) if cl_exe is None: scons_logger.sysexit( "Error, Visual Studio required for using ClangCL on Windows.") clang_dir = os.path.join(cl_exe[:cl_exe.lower().rfind("msvc")], "Llvm") if (getCompilerArch(mingw_mode=False, msvc_mode=True, the_cc_name="cl.exe", compiler_path=cl_exe) == "pei-x86-64"): clang_dir = os.path.join(clang_dir, "x64", "bin") else: clang_dir = os.path.join(clang_dir, "bin") if not os.path.exists(clang_dir): scons_details_logger.sysexit( "Visual Studio has no Clang component found at '%s'." % clang_dir) scons_details_logger.info( "Adding Visual Studio directory '%s' for Clang to PATH." % clang_dir) addToPATH(env, clang_dir, prefix=True) clangcl_path = getExecutablePath("clang-cl", env=env) if clangcl_path is None: scons_details_logger.sysexit( "Visual Studio has no Clang component found at '%s'." % clang_dir) env["CC"] = "clang-cl" env["LINK"] = "lld-link" env["CCVERSION"] = None
def addConstantBlobFile(env, resource_mode, source_dir, c11_mode, mingw_mode, target_arch): constants_bin_filename = getConstantBlobFilename(source_dir) scons_details_logger.info("Using resource mode: %r." % resource_mode) if resource_mode == "win_resource": # On Windows constants can be accessed as a resource by Nuitka runtime afterwards. env.Append(CPPDEFINES=["_NUITKA_CONSTANTS_FROM_RESOURCE"]) elif resource_mode == "incbin": env.Append(CPPDEFINES=["_NUITKA_CONSTANTS_FROM_INCBIN"]) constants_generated_filename = os.path.join(source_dir, "__constants_data.c") with open(constants_generated_filename, "w") as output: output.write(""" #define INCBIN_PREFIX #define INCBIN_STYLE INCBIN_STYLE_SNAKE #define INCBIN_LOCAL #include "nuitka/incbin.h" INCBIN(constant_bin, "__constants.bin"); unsigned char const *getConstantsBlobData() { return constant_bin_data; } """) elif resource_mode == "linker": # On Windows constants are accesses as a resource by Nuitka afterwards. env.Append(CPPDEFINES=["_NUITKA_CONSTANTS_FROM_LINKER"]) env.Append(LINKFLAGS=[ "-Wl,-b", "-Wl,binary", "-Wl,%s" % constants_bin_filename, "-Wl,-b", "-Wl,%s" % getLinkerArch(target_arch=target_arch, mingw_mode=mingw_mode), "-Wl,-defsym", "-Wl,%sconstant_bin=_binary_%s___constants_bin_start" % ( "_" if mingw_mode else "", "".join(re.sub("[^a-zA-Z0-9_]", "_", c) for c in source_dir), ), ]) elif resource_mode == "code": constants_generated_filename = os.path.join(source_dir, "__constants_data.c") def writeConstantsDataSource(): with open(constants_generated_filename, "w") as output: if not c11_mode: output.write('extern "C" ') output.write("const unsigned char constant_bin[] =\n{\n") with open(constants_bin_filename, "rb") as f: content = f.read() for count, stream_byte in enumerate(content): if count % 16 == 0: if count > 0: output.write("\n") output.write(" ") if str is bytes: stream_byte = ord(stream_byte) output.write(" 0x%02x," % stream_byte) output.write("\n};\n") writeConstantsDataSource() else: scons_logger.sysexit("Error, illegal resource mode %r specified" % resource_mode)
def _injectCcache(the_compiler, cc_path, env, python_prefix, assume_yes_for_downloads): ccache_binary = os.environ.get("NUITKA_CCACHE_BINARY") # If not provided, search it in PATH and guessed directories. if ccache_binary is None: ccache_binary = getExecutablePath("ccache", env=env) if ccache_binary is None: for candidate in _getCcacheGuessedPaths(python_prefix): scons_details_logger.info( "Checking if ccache is at '%s' guessed path." % candidate ) if os.path.exists(candidate): ccache_binary = candidate scons_details_logger.info( "Using ccache '%s' from guessed path." % ccache_binary ) break if ccache_binary is None and os.name == "nt": url = "https://github.com/ccache/ccache/releases/download/v3.7.12/ccache-3.7.12-windows-32.zip" ccache_binary = getCachedDownload( url=url, is_arch_specific=False, specifity=url.rsplit("/", 2)[1], flatten=True, binary="ccache.exe", message="Nuitka will make use of ccache to speed up repeated compilation.", reject=None, assume_yes_for_downloads=assume_yes_for_downloads, ) else: scons_details_logger.info( "Using ccache '%s' from NUITKA_CCACHE_BINARY environment variable." % ccache_binary ) if ccache_binary is not None and os.path.exists(ccache_binary): # Make sure the # In case we are on Windows, make sure the Anaconda form runs outside of Anaconda # environment, by adding DLL folder to PATH. assert getExecutablePath(os.path.basename(the_compiler), env=env) == cc_path # We use absolute paths for CC, pass it like this, as ccache does not like absolute. env["CXX"] = env["CC"] = '"%s" "%s"' % (ccache_binary, cc_path) # Spare ccache the detection of the compiler, seems it will also misbehave when it's # prefixed with "ccache" on old gcc versions in terms of detecting need for C++ linkage. env["LINK"] = cc_path scons_details_logger.info( "Found ccache '%s' to cache C compilation result." % ccache_binary ) scons_details_logger.info( "Providing real CC path '%s' via PATH extension." % cc_path ) else: if isWin32Windows(): scons_logger.warning( "Didn't find ccache for C level caching, follow Nuitka user manual description." )
def addConstantBlobFile(env, resource_desc, source_dir, target_arch): resource_mode, reason = resource_desc constants_bin_filename = getConstantBlobFilename(source_dir) scons_details_logger.info("Using resource mode: '%s' (%s)." % (resource_mode, reason)) if resource_mode == "win_resource": # On Windows constants can be accessed as a resource by Nuitka runtime afterwards. env.Append(CPPDEFINES=["_NUITKA_CONSTANTS_FROM_RESOURCE"]) elif resource_mode == "incbin": env.Append(CPPDEFINES=["_NUITKA_CONSTANTS_FROM_INCBIN"]) constants_generated_filename = os.path.join(source_dir, "__constants_data.c") putTextFileContents( constants_generated_filename, contents=r""" #define INCBIN_PREFIX #define INCBIN_STYLE INCBIN_STYLE_SNAKE #define INCBIN_LOCAL #ifdef _NUITKA_EXPERIMENTAL_WRITEABLE_CONSTANTS #define INCBIN_OUTPUT_SECTION ".data" #endif #include "nuitka/incbin.h" INCBIN(constant_bin, "%(constants_bin_filename)s"); unsigned char const *getConstantsBlobData(void) { return constant_bin_data; } """ % {"constants_bin_filename": os.path.join(source_dir, "__constants.bin")}, ) elif resource_mode == "linker": # Indicate "linker" resource mode. env.Append(CPPDEFINES=["_NUITKA_CONSTANTS_FROM_LINKER"]) env.Append(LINKFLAGS=[ "-Wl,-b", "-Wl,binary", "-Wl,%s" % constants_bin_filename, "-Wl,-b", "-Wl,%s" % getLinkerArch(target_arch=target_arch, mingw_mode=env.mingw_mode), "-Wl,-defsym", "-Wl,%sconstant_bin_data=_binary_%s___constants_bin_start" % ( "_" if env.mingw_mode else "", "".join(re.sub("[^a-zA-Z0-9_]", "_", c) for c in source_dir), ), ]) elif resource_mode == "code": # Indicate "code" resource mode. env.Append(CPPDEFINES=["_NUITKA_CONSTANTS_FROM_CODE"]) constants_generated_filename = os.path.join(source_dir, "__constants_data.c") def writeConstantsDataSource(): with openTextFile(constants_generated_filename, "w") as output: if not env.c11_mode: output.write('extern "C" {') output.write(""" // Constant data for the program. #if !defined(_NUITKA_EXPERIMENTAL_WRITEABLE_CONSTANTS) const #endif unsigned char constant_bin_data[] =\n{\n """) with open(constants_bin_filename, "rb") as f: content = f.read() for count, stream_byte in enumerate(content): if count % 16 == 0: if count > 0: output.write("\n") output.write(" ") if str is bytes: stream_byte = ord(stream_byte) output.write(" 0x%02x," % stream_byte) output.write("\n};\n") if not env.c11_mode: output.write("}") writeConstantsDataSource() else: scons_logger.sysexit("Error, illegal resource mode %r specified" % resource_mode)
def checkWindowsCompilerFound(env, target_arch, clang_mode, msvc_version, assume_yes_for_downloads): """Remove compiler of wrong arch or too old gcc and replace with downloaded winlibs gcc.""" if os.name == "nt": # On Windows, in case MSVC was not found and not previously forced, use the # winlibs MinGW64 as a download, and use it as a fallback. compiler_path = getExecutablePath(env["CC"], env=env) scons_details_logger.info("Checking usability of %r from %r" % (compiler_path, env["CC"])) # Drop wrong arch compiler, most often found by scans. There might be wrong gcc or cl on the PATH. if compiler_path is not None: the_cc_name = os.path.basename(compiler_path) decision, linker_arch, compiler_arch = decideArchMismatch( target_arch=target_arch, mingw_mode=isGccName(the_cc_name), msvc_mode=not isGccName(the_cc_name), the_cc_name=the_cc_name, compiler_path=compiler_path, ) if decision: scons_logger.info( "Mismatch between Python binary (%r -> %r) and C compiler (%r -> %r) arches, that compiler is ignored!" % ( os.environ["NUITKA_PYTHON_EXE_PATH"], linker_arch, compiler_path, compiler_arch, )) # This will trigger using it to use our own gcc in branch below. compiler_path = None env["CC"] = None if compiler_path is not None and msvc_version is not None: if msvc_version == "latest": scons_logger.info("MSVC version resolved to %s." % getMsvcVersionString(env)) # Requested a specific MSVC version, check if that worked. elif msvc_version != getMsvcVersionString(env): scons_logger.info( "Failed to find requested MSVC version (%r != %r)." % (msvc_version, getMsvcVersionString(env))) # This will trigger error exit in branch below. compiler_path = None env["CC"] = None if compiler_path is not None: the_cc_name = os.path.basename(compiler_path) if isGccName(the_cc_name): gcc_version = myDetectVersion(env, compiler_path) min_version = (11, 2) if gcc_version is not None and (gcc_version < min_version or "force-winlibs-gcc" in env.experimental_flags): scons_logger.info( "Too old gcc %r (%r < %r) ignored!" % (compiler_path, gcc_version, min_version)) # This also will trigger using it to use our own gcc in branch below. compiler_path = None env["CC"] = None if compiler_path is None and msvc_version is None: scons_details_logger.info( "No usable C compiler, attempt fallback to winlibs gcc.") # This will download "gcc.exe" (and "clang.exe") when all others have been # rejected and MSVC is not enforced. compiler_path = getCachedDownloadedMinGW64( target_arch=target_arch, assume_yes_for_downloads=assume_yes_for_downloads, ) addToPATH(env, os.path.dirname(compiler_path), prefix=True) env = createEnvironment( mingw_mode=True, msvc_version=None, target_arch=target_arch, experimental=env.experimental_flags, ) if clang_mode: env["CC"] = os.path.join(os.path.dirname(compiler_path), "clang.exe") if env["CC"] is None: raiseNoCompilerFoundErrorExit() return env
def _enableLtoSettings( env, lto_mode, pgo_mode, job_count, ): # This is driven by branches on purpose and pylint: disable=too-many-branches,too-many-statements orig_lto_mode = lto_mode if lto_mode == "no": lto_mode = False reason = "disabled" elif lto_mode == "yes": lto_mode = True reason = "enabled" elif pgo_mode in ("use", "generate"): lto_mode = True reason = "PGO implies LTO" elif env.msvc_mode and getMsvcVersion(env) >= 14: lto_mode = True reason = "known to be supported" elif env.nuitka_python: lto_mode = True reason = "known to be supported (Nuitka-Python)" elif (env.debian_python and env.gcc_mode and not env.clang_mode and env.gcc_version >= (6, )): lto_mode = True reason = "known to be supported (Debian)" elif env.gcc_mode and env.the_cc_name == "gnu-cc": lto_mode = True reason = "known to be supported (CondaCC)" elif env.mingw_mode and env.clang_mode: lto_mode = False reason = "known to not be supported (new MinGW64 Clang)" elif env.gcc_mode and env.mingw_mode and env.gcc_version >= (11, 2): lto_mode = True reason = "known to be supported (new MinGW64)" else: lto_mode = False reason = "not known to be supported" if lto_mode and env.gcc_mode and not env.clang_mode and env.gcc_version < ( 4, 6): scons_logger.warning("""\ The gcc compiler %s (version %s) doesn't have the sufficient \ version for lto mode (>= 4.6). Disabled.""" % (env["CXX"], env["CXXVERSION"])) lto_mode = False reason = "gcc 4.6 is doesn't have good enough LTO support" if env.gcc_mode and lto_mode: env.Append(CCFLAGS=["-flto"]) if env.clang_mode: env.Append(LINKFLAGS=["-flto"]) else: env.Append(CCFLAGS=["-fuse-linker-plugin", "-fno-fat-lto-objects"]) env.Append(LINKFLAGS=["-fuse-linker-plugin"]) env.Append(LINKFLAGS=["-flto=%d" % job_count]) # Need to tell the linker these things are OK. env.Append(LINKFLAGS=["-fpartial-inlining", "-freorder-functions"]) # Tell compiler to use link time optimization for MSVC if env.msvc_mode and lto_mode: env.Append(CCFLAGS=["/GL"]) if not env.clangcl_mode: env.Append(LINKFLAGS=["/LTCG"]) if orig_lto_mode == "auto": scons_details_logger.info( "LTO mode auto was resolved to mode: '%s' (%s)." % ("yes" if lto_mode else "no", reason)) env.lto_mode = lto_mode # PGO configuration _enablePgoSettings(env, pgo_mode)
def _injectCcache(env, cc_path, python_prefix, target_arch, assume_yes_for_downloads): ccache_binary = os.environ.get("NUITKA_CCACHE_BINARY") # If not provided, search it in PATH and guessed directories. if ccache_binary is None: ccache_binary = getExecutablePath("ccache", env=env) if ccache_binary is None: for candidate in _getCcacheGuessedPaths(python_prefix): scons_details_logger.info( "Checking if ccache is at '%s' guessed path." % candidate) if os.path.exists(candidate): ccache_binary = candidate scons_details_logger.info( "Using ccache '%s' from guessed path." % ccache_binary) break if ccache_binary is None: if isWin32Windows(): url = "https://github.com/ccache/ccache/releases/download/v3.7.12/ccache-3.7.12-windows-32.zip" ccache_binary = getCachedDownload( url=url, is_arch_specific=False, specificity=url.rsplit("/", 2)[1], flatten=True, binary="ccache.exe", message= "Nuitka will make use of ccache to speed up repeated compilation.", reject=None, assume_yes_for_downloads=assume_yes_for_downloads, ) elif isMacOS(): # TODO: Do not yet have M1 access to create one and 10.14 is minimum # we managed to compile ccache for. if target_arch != "arm64" and tuple( int(d) for d in platform.release().split(".")) >= (18, 2): url = "https://nuitka.net/ccache/v4.2.1/ccache-4.2.1.zip" ccache_binary = getCachedDownload( url=url, is_arch_specific=False, specificity=url.rsplit("/", 2)[1], flatten=True, binary="ccache", message= "Nuitka will make use of ccache to speed up repeated compilation.", reject=None, assume_yes_for_downloads=assume_yes_for_downloads, ) else: scons_details_logger.info( "Using ccache '%s' from NUITKA_CCACHE_BINARY environment variable." % ccache_binary) if ccache_binary is not None and os.path.exists(ccache_binary): # Make sure the # In case we are on Windows, make sure the Anaconda form runs outside of Anaconda # environment, by adding DLL folder to PATH. assert areSamePaths( getExecutablePath(os.path.basename(env.the_compiler), env=env), cc_path) # We use absolute paths for CC, pass it like this, as ccache does not like absolute. env["CXX"] = env["CC"] = '"%s" "%s"' % (ccache_binary, cc_path) # Spare ccache the detection of the compiler, seems it will also misbehave when it's # prefixed with "ccache" on old gcc versions in terms of detecting need for C++ linkage. env["LINK"] = cc_path scons_details_logger.info( "Found ccache '%s' to cache C compilation result." % ccache_binary) scons_details_logger.info( "Providing real CC path '%s' via PATH extension." % cc_path)