diff --git a/.efrocachemap b/.efrocachemap
index 65a92d4a..31549b72 100644
--- a/.efrocachemap
+++ b/.efrocachemap
@@ -4117,8 +4117,8 @@
"assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe",
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8c/ae/8d2561ca2c4bb1bb033560866410",
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/74/2b/eea5b942b0cead421529d09039cd",
- "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/41/22/06f954698bd228a23c0423830236",
+ "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/75/f5/740ce4ae3fc843c4cec96967f75a",
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d0/1f/573bbb85fbb6a3bf8a056caeeaf9",
- "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5b/5b/1dcc8ebb16f82a08531c945909fb",
- "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f8/d7/dc541bfca363ead79e0c3edf6d61"
+ "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/35/6d/c5e69424a36f80c0fac65dc684ca",
+ "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a6/83/e3ed78e10bf251b44168ddd73600"
}
\ No newline at end of file
diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
index b0417386..63761c7a 100644
--- a/.idea/dictionaries/ericf.xml
+++ b/.idea/dictionaries/ericf.xml
@@ -151,8 +151,11 @@
bbot
bbtn
bcppcompiler
+ bdfl
belarussian
benboncan
+ bfiledir
+ bfiles
bgmodel
bgterrain
bgtex
@@ -191,6 +194,7 @@
bsfoundation
bsmaster
bsmusic
+ bsources
bsplaylist
bsremote
bsstd
@@ -290,6 +294,7 @@
clrhdr
clrred
cmathmodule
+ cmds
cmembers
cmodel
cnode
@@ -845,6 +850,7 @@
inits
inmobi
inpath
+ inpaths
inputdevice
inputfiles
inputhash
@@ -1322,6 +1328,7 @@
priceraw
printnodes
printobjects
+ printpaths
priv
proactor
proc
@@ -1675,6 +1682,7 @@
taobaomascot
targ
targetdir
+ targetname
targetpath
targetpractice
tbtcolor
diff --git a/Makefile b/Makefile
index bc3eb668..ceb95143 100644
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,23 @@
# Prefix used for output of docs/changelogs/etc targets for use in webpages.
DOCPREFIX = "ballisticacore_"
+# This setup lets us set up files "bfiles" for expensive dummy targets
+# to avoid re-running them every time. An good use case is VM build targets
+# where just spinning up the VM to confirm that nothing needs rebuilding is
+# time-consuming. To use these, do the following:
+# - create a physical file for the target: ${BFILEDIR}/targetname
+# (targets that are already physical files work too)
+# - add this dependency to it: ${shell ${BSOURCES} }
+# (where covers all files that could affect the target)
+# - always touch the target file as the last build step:
+# mkdir -p `dirname ${@}` && touch ${@}
+# (even if the build step usually does; the build may not actually run
+# which could leave one of the overly-broad dep files newer than it)
+# Note that this mechanism slows builds a bit if category contains a lot of
+# files, so is not always a win.
+BFILEDIR = .cache/bfile
+BSOURCES = tools/snippets sources
+
################################################################################
# #
@@ -86,6 +103,18 @@ assets-android: prereqs
assets-clean:
@cd assets && $(MAKE) clean
+# A bfile for the resources target so we don't always have to run it.
+RESOURCES_F = ${BFILEDIR}/resources
+${RESOURCES_F}: ${PREREQS} resources/Makefile ${shell ${BSOURCES} resources}
+ @cd resources && $(MAKE) -j${CPUS} resources
+ @mkdir -p `dirname ${@}` && touch ${@}
+
+# A bfile for the code target so we don't always have to run it.
+CODE_F = ${BFILEDIR}/code
+${CODE_F}: ${PREREQS} ${shell ${BSOURCES} gen}
+ @cd src/generated_src && $(MAKE) -j${CPUS} generated_code
+ @mkdir -p `dirname ${@}` && touch ${@}
+
# Remove *ALL* files and directories that aren't managed by git
# (except for a few things such as localconfig.json).
clean:
diff --git a/tools/efrotools/efrocache.py b/tools/efrotools/efrocache.py
index a4956445..3d963fdd 100644
--- a/tools/efrotools/efrocache.py
+++ b/tools/efrotools/efrocache.py
@@ -202,6 +202,12 @@ def update_cache(makefile_dirs: List[str]) -> None:
else:
fnames2.append(fullpath)
+ # if bool(True):
+ # print("1", fnames1)
+ # print("2", fnames2)
+ # print('SO FAR SO GOOD')
+ # sys.exit(0)
+
staging_dir = 'build/efrocache'
mapping_file = 'build/efrocachemap'
run(f'rm -rf {staging_dir}')
@@ -224,32 +230,6 @@ def update_cache(makefile_dirs: List[str]) -> None:
print(f'Cache update successful!')
-def _write_cache_file(staging_dir: str, fname: str) -> Tuple[str, str]:
- import hashlib
- from efrotools import run
- print(f'Caching {fname}')
- if ' ' in fname:
- raise RuntimeError('Spaces in paths not supported.')
-
- # Just going with ol' md5 here; we're the only ones creating these so
- # security isn't a concern.
- md5 = hashlib.md5()
- with open(fname, 'rb') as infile:
- md5.update(infile.read())
- md5.update(fname.encode())
- finalhash = md5.hexdigest()
- hashpath = os.path.join(finalhash[:2], finalhash[2:4], finalhash[4:])
- path = os.path.join(staging_dir, hashpath)
- os.makedirs(os.path.dirname(path), exist_ok=True)
-
- # Fancy pipe stuff which will give us deterministic
- # tar.gz files (no embedded timestamps)
- # Note: The 'COPYFILE_DISABLE' prevents mac tar from adding
- # file attributes/resource-forks to the archive as as ._filename.
- run(f'COPYFILE_DISABLE=1 tar cf - {fname} | gzip -n > {path}')
- return fname, hashpath
-
-
def _write_cache_files(fnames1: List[str], fnames2: List[str],
staging_dir: str, mapping_file: str) -> None:
fhashes1: Set[str] = set()
@@ -301,6 +281,32 @@ def _write_cache_files(fnames1: List[str], fnames2: List[str],
outfile.write(json.dumps(mapping, indent=2, sort_keys=True))
+def _write_cache_file(staging_dir: str, fname: str) -> Tuple[str, str]:
+ import hashlib
+ from efrotools import run
+ print(f'Caching {fname}')
+ if ' ' in fname:
+ raise RuntimeError('Spaces in paths not supported.')
+
+ # Just going with ol' md5 here; we're the only ones creating these so
+ # security isn't a concern.
+ md5 = hashlib.md5()
+ with open(fname, 'rb') as infile:
+ md5.update(infile.read())
+ md5.update(fname.encode())
+ finalhash = md5.hexdigest()
+ hashpath = os.path.join(finalhash[:2], finalhash[2:4], finalhash[4:])
+ path = os.path.join(staging_dir, hashpath)
+ os.makedirs(os.path.dirname(path), exist_ok=True)
+
+ # Fancy pipe stuff which will give us deterministic
+ # tar.gz files (no embedded timestamps)
+ # Note: The 'COPYFILE_DISABLE' prevents mac tar from adding
+ # file attributes/resource-forks to the archive as as ._filename.
+ run(f'COPYFILE_DISABLE=1 tar cf - {fname} | gzip -n > {path}')
+ return fname, hashpath
+
+
def _check_warm_start_entry(entry: Tuple[str, str]) -> None:
import hashlib
fname, filehash = entry
diff --git a/tools/snippets b/tools/snippets
index 823f30bc..120e9fe3 100755
--- a/tools/snippets
+++ b/tools/snippets
@@ -876,5 +876,68 @@ def update_makebob() -> None:
print('All builds complete!', flush=True)
+def _printpaths(inpaths: List[str], category: str) -> None:
+ paths: List[str] = []
+ for inpath in inpaths:
+ # Add files verbatim; recurse through dirs.
+ if os.path.isfile(inpath):
+ paths.append(inpath)
+ continue
+ for root, _dnames, fnames in os.walk(inpath):
+ # Always skip these..
+ if (root.startswith('src/generated_src')
+ or root.startswith('src/tools')):
+ continue
+ # Skip some of these...
+ if root.startswith('src/external'):
+ if category == 'win' and root.startswith(
+ 'src/external/windows'):
+ pass
+ else:
+ continue
+ # Ignore python cache files.
+ if '__pycache__' in root:
+ continue
+ for fname in fnames:
+ # Ignore dot files
+ if fname.startswith('.'):
+ continue
+ path = os.path.join(root, fname)
+ if ' ' in path:
+ raise RuntimeError(f'Invalid path with space: {path}')
+ paths.append(path)
+ print(' '.join(paths))
+
+
+def sources() -> None:
+ """Print source files of different categories.
+
+ These are used as broad, redundant filters for expensive build ops.
+ For instance, when running a build through a VM we might want to skip
+ even spinning up the VM if absolutely no source files have changed.
+ """
+ try:
+ if len(sys.argv) != 3:
+ raise CleanError('Expected one argument.')
+ category = sys.argv[2]
+ if category == 'gen':
+ _printpaths(['tools', 'src/generated_src'], category)
+ elif category == 'assets':
+ _printpaths(['tools', 'assets/src'], category)
+ elif category in ('cmake', 'win'):
+ _printpaths(['tools', 'src'], category)
+ elif category == 'resources':
+ _printpaths(['tools', 'resources/src', 'resources/Makefile'],
+ category)
+ else:
+ raise ValueError(f'Invalid source category: {category}')
+
+ except Exception as exc:
+ # We're used by ${shell} cmds in Makefiles so need to fail in a
+ # fashion that is noticeable there:
+ print(f'Error in sources snippet: {exc}', file=sys.stderr)
+ print('__nonexistent_error_output__')
+
+
if __name__ == '__main__':
snippets_main(globals())