Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 48 additions & 9 deletions system/lib/update_common.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import os
import sys
import shutil
import re
import argparse

script_dir = os.path.abspath(os.path.dirname(__file__))
emscripten_root = os.path.dirname(os.path.dirname(script_dir))
default_llvm_dir = os.path.join(os.path.dirname(emscripten_root), 'llvm-project')


def get_llvm_dir():
if len(sys.argv) > 1:
llvm_dir = os.path.abspath(sys.argv[1])
else:
llvm_dir = default_llvm_dir
if not os.path.isdir(llvm_dir):
print(f'LLVM directory not found: {llvm_dir}', file=sys.stderr)
print(f'Usage: {sys.argv[0]} [llvm_dir]', file=sys.stderr)
def parse_args(default_dir, dir_name='llvm_dir'):
parser = argparse.ArgumentParser(description=f'Update library from {dir_name}')
parser.add_argument('src_dir', nargs='?', default=default_dir, help=f'Path to {dir_name}')
args = parser.parse_args()

src_dir = os.path.abspath(args.src_dir)
if not os.path.isdir(src_dir):
print(f'{dir_name} directory not found: {src_dir}', file=sys.stderr)
parser.print_help(sys.stderr)
sys.exit(1)
return llvm_dir

return src_dir


def clean_dir(dirname, preserve_files=()):
Expand Down Expand Up @@ -47,3 +51,38 @@ def copy_tree(upstream_dir, local_dir, excludes=()):
if f in excludes:
full = os.path.join(root, f)
os.remove(full)


def get_llvm_version(upstream_dir):
cmake_file = os.path.join(upstream_dir, 'cmake', 'Modules', 'LLVMVersion.cmake')
if not os.path.exists(cmake_file):
return None, None
with open(cmake_file, 'r') as f:
content = f.read()
major = re.search(r'set\(LLVM_VERSION_MAJOR\s+(\d+)\)', content)
minor = re.search(r'set\(LLVM_VERSION_MINOR\s+(\d+)\)', content)
patch = re.search(r'set\(LLVM_VERSION_PATCH\s+(\d+)\)', content)
if major and minor and patch:
return major.group(1), f'{major.group(1)}.{minor.group(1)}.{patch.group(1)}'
return None, None


def update_readme(local_dir, llvm_dir):
readme_path = os.path.join(local_dir, 'readme.txt')
if not os.path.exists(readme_path):
readme_path = os.path.join(local_dir, 'README.txt')
if not os.path.exists(readme_path):
return

with open(readme_path, 'r') as f:
content = f.read()

major, full_version = get_llvm_version(llvm_dir)
if major and full_version:
# Find full version numbers in the form of x.y.z and update them
content = re.sub(r'\b\d+\.\d+\.\d+\b', full_version, content)
# Find 'emscripten-libs-NN' strings and update them with the major version
content = re.sub(r'emscripten-libs-\d+', f'emscripten-libs-{major}', content)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we determine this branch name by looking that the git log?

Maybe git describe (or something like it) should always show emscripten-libs-xx?

Ah yes I think you can do git branch --contains HEAD to show all the branchs that contains HEAD, there should always be one of them called emscripten-libs-xx

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we determine this branch name by looking that the git log?

As I said in #27254 (comment), my local branch name while I'm working on this is not emscripten-libs-22, because it is a work in progress. In my case that is emscripten-libs-22-downstream, but it may be some temporary names like changes for others.

Maybe git describe (or something like it) should always show emscripten-libs-xx?

git describe finds the most recent tag reachable from a commit and creates a human-readable string. In my case it returns llvmorg-22.1.8-1-gf4d109d42671 (not emscripten-libs-22-downstream or whatever) so it's not related to a branch name.

Ah yes I think you can do git branch --contains HEAD to show all the branchs that contains HEAD, there should always be one of them called emscripten-libs-xx

Again, for me this is emscripten-libs-22-downstream, not emscripten-libs-22. The branch name in my local LLVM directory is not emscripten-libs-22. I can't make it emscripten-libs-22 because this is a work in progress. After fixing all tests I'll push all final changes to the LLVM directory and commit them to emscripten-libs-22.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But can't we make it so that all local changes are always based on some emscripten-libs-XX?

At least for followup changes they should always be true right?

Maybe for the initial change you could create the initial emscripten-libs-22 branch and point it directly at llvmorg-22.X.Y and then have emscripten-libs-22-downstream (your local work) be branch that targets that?

If its too complicated than no worries. I'm not a huge fan of parsing the llvm CMakeFile here but maybe its the best way?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But can't we make it so that all local changes are always based on some emscripten-libs-XX?
At least for followup changes they should always be true right?

What do you mean by "based on"? My local branch emscripten-libs-22-downstream is based on, or on top of, emscripten-libs-22. But the branch name itself is not emscripten-libs-22 and git branch --contains HEAD does not return emscripten-libs-22. If I we really want to make the branch name emscripten-libs-22 while I'm working on this, I shouldn't even locally commit my cherry-picked changes to my LLVM directory.

This is my current git log result:

commit f4d109d42671ad1fe3153c50638ec39d583a6cec (HEAD -> emscripten-libs-22-downstream, origin/emscripten-libs-22-downstream)
Author: Heejin Ahn <aheejin@gmail.com>
Date:   Fri Jul 3 01:05:24 2026 +0000

    Add downstream changes from Emscripten
    
    This adds all cumulative downstream changes so far to emscripten-libs-22
    branch (which currently is at llvmorg-22.1.8 upstream tag).

commit ca7933e47d3a3451d81e72ac174dcb5aa28b59d1 (tag: llvmorg-22.1.8, upstream/release/22.x, origin/emscripten-libs-22, emscripten-libs-22)
Author: William Tran-Viet <wtranviet@proton.me>
Date:   Wed Apr 29 06:15:45 2026 -0400

    [libc++] Disable mistakenly enabled `optional<T&>` constructors for `optional<T>` (#194446)
    
    Resolves #194415
    
    - A constructor specifically meant for `optional<T&>` was left enabled
    for `optional<T>`
    - Fix it, and add a test to check for regression.
    - This patch also corrects the constraints for `optional(optional<U>&)`
    and `optional(const optional<U>&)` , as they were incorrectly
    disallowing [valid conversions](https://godbolt.org/z/1r5Ea7z5M)
    - Also, correct the `noexcept` specification.
    - Add tests for both corrections.
    
    (cherry picked from commit 239189ca28847aa4797368827107c22c32080509)

Maybe for the initial change you could create the initial emscripten-libs-22 branch and point it directly at llvmorg-22.X.Y and then have emscripten-libs-22-downstream (your local work) be branch that targets that?

Not sure what "have emscripten-libs-22-downstream (yur local work) be branch that targets that" means. See my git log result. It's on top of emscripten-libs-22.

If its too complicated than no worries. I'm not a huge fan of parsing the llvm CMakeFile here but maybe its the best way?

I don't know where else we can get the full version number. (Parsing that cmake file was Gemini's suggestion) Do you suggest elsewhere?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see.

I think I was misunderstand what git branch --contains HEAD did. I was hoping that git branch --contains HEAD would print (in your case) emscripten-libs-22-downstream and emscripten-libs-22 and release-22.x but it looks like --contains doesn't actually do that.

You can use it find all the branchs from release-22.x I guess:

$ git branch -a --contains upstream/release/22.x
  remotes/emscripten/emscripten-libs-22
  remotes/emscripten/emscripten-libs-22-downstream
  remotes/upstream/release/22.x

But that isn't what we want here. What I was hoping for was a way to find find all the branches that exist in the history of HEAD.. but maybe there is no easy way to get that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need too much high-tech (?) solution here anyway, and as long as we don't change our LLVM library branch name convention (emscripten-libs-NN) this will work. If we ever change it we can do an one-time update to the script too.


with open(readme_path, 'w') as f:
f.write(content)
3 changes: 2 additions & 1 deletion system/lib/update_compiler_rt.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@


def main():
llvm_dir = get_llvm_dir()
llvm_dir = parse_args(default_llvm_dir, 'llvm_dir')
upstream_dir = os.path.join(llvm_dir, 'compiler-rt')
assert os.path.exists(upstream_dir)
upstream_src = os.path.join(upstream_dir, 'lib', 'builtins')
Expand All @@ -53,6 +53,7 @@ def main():

shutil.copy2(os.path.join(upstream_dir, 'CREDITS.TXT'), local_src)
shutil.copy2(os.path.join(upstream_dir, 'LICENSE.TXT'), local_src)
update_readme(local_src, llvm_dir)


if __name__ == '__main__':
Expand Down
2 changes: 2 additions & 0 deletions system/lib/update_libcxx.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def generate_modules(cmake_version: str):
shutil.copytree(dist, dst, dirs_exist_ok=True)

def main():
llvm_dir = parse_args(default_llvm_dir, 'llvm_dir')
# Exit early if cmake is not found
try:
output= subprocess.check_output(['cmake', '--version'], text=True)
Expand Down Expand Up @@ -112,6 +113,7 @@ def main():
copy_tree(upstream_dir, local_dir, excludes)

shutil.copy2(os.path.join(libc_upstream_dir, 'LICENSE.TXT'), libc_local_dir)
update_readme(local_root, llvm_dir)

if __name__ == '__main__':
main()
3 changes: 2 additions & 1 deletion system/lib/update_libcxxabi.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@


def main():
llvm_dir = get_llvm_dir()
llvm_dir = parse_args(default_llvm_dir, 'llvm_dir')
Comment thread
sbc100 marked this conversation as resolved.
upstream_root = os.path.join(llvm_dir, 'libcxxabi')
upstream_src = os.path.join(upstream_root, 'src')
upstream_inc = os.path.join(upstream_root, 'include')
Expand All @@ -34,6 +34,7 @@ def main():
copy_tree(upstream_inc, local_inc, excludes)
shutil.copy2(os.path.join(upstream_root, 'CREDITS.TXT'), local_root)
shutil.copy2(os.path.join(upstream_root, 'LICENSE.TXT'), local_root)
update_readme(local_root, llvm_dir)


if __name__ == '__main__':
Expand Down
3 changes: 2 additions & 1 deletion system/lib/update_libunwind.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@


def main():
llvm_dir = get_llvm_dir()
llvm_dir = parse_args(default_llvm_dir, 'llvm_dir')
upstream_root = os.path.join(llvm_dir, 'libunwind')
upstream_src = os.path.join(upstream_root, 'src')
upstream_inc = os.path.join(upstream_root, 'include')
Expand All @@ -33,6 +33,7 @@ def main():
copy_tree(upstream_src, local_src, excludes)
copy_tree(upstream_inc, local_inc, excludes)
shutil.copy2(os.path.join(upstream_root, 'LICENSE.TXT'), local_root)
update_readme(local_root, llvm_dir)


if __name__ == '__main__':
Expand Down
4 changes: 3 additions & 1 deletion system/lib/update_llvm_libc.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@


def main():
llvm_dir = get_llvm_dir()
llvm_dir = parse_args(default_llvm_dir, 'llvm_dir')
libc_upstream_dir = os.path.join(llvm_dir, 'libc')
assert os.path.exists(libc_upstream_dir)
libc_local_dir = os.path.join(script_dir, 'llvm-libc')
Expand All @@ -66,5 +66,7 @@ def main():
for file in files_to_exclude:
os.remove(file)

update_readme(libc_local_dir, llvm_dir)

if __name__ == '__main__':
main()
11 changes: 1 addition & 10 deletions system/lib/update_musl.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,6 @@
)


if len(sys.argv) > 1:
musl_dir = os.path.abspath(sys.argv[1])
else:
musl_dir = default_musl_dir
if not os.path.isdir(musl_dir):
print(f'musl directory not found: {musl_dir}', file=sys.stderr)
print(f'Usage: {sys.argv[0]} [musl_dir]', file=sys.stderr)
sys.exit(1)


def make_ignore(root):
root = Path(root).resolve()

Expand All @@ -102,6 +92,7 @@ def ignore(directory, contents):


def main():
musl_dir = parse_args(default_musl_dir, 'musl_dir')
assert os.path.exists(musl_dir)

# Remove old version
Expand Down