-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add contrib ports (Contrib ports part 2) #21244
Changes from all commits
19f0583
d135cd4
27db0bd
831c523
0bfdef3
177d603
7d43831
5d0afbb
f6694fe
ba2a1ff
b88e332
aeb2d0a
9facf38
6717313
0344a99
2be2672
d7a3b45
dc92707
b028587
4f9e599
51ae73d
ec050d1
033e0ba
c5d2f99
db88e52
3d727b9
5a0b668
124d52b
22a392a
93c5ea7
0953955
21a2839
44758b0
3df103f
a1512be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
.. _Contrib-Ports: | ||
|
||
======================== | ||
Emscripten Contrib Ports | ||
======================== | ||
|
||
Contrib ports are contributed by the wider community and | ||
supported on a "best effort" basis. Since they are not run as part | ||
of emscripten CI they are not always guaranteed to build or function. | ||
|
||
The following is the complete list of the contrib ports that are | ||
available in emscripten. In order to use a contrib port you use the | ||
``--use-port=<port_name>`` option (:ref:`emcc <emcc-use-port>`). | ||
|
||
.. _contrib.glfw3: | ||
|
||
contrib.glfw3 | ||
============= | ||
|
||
This project is an emscripten port of glfw written in C++ for the web/webassembly platform | ||
|
||
`Project information <https://github.com/pongasoft/emscripten-glfw>`_ | ||
|
||
License: Apache 2.0 license |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Copyright 2024 The Emscripten Authors. All rights reserved. | ||
* Emscripten is available under two separate licenses, the MIT license and the | ||
* University of Illinois/NCSA Open Source License. Both these licenses can be | ||
* found in the LICENSE file. | ||
*/ | ||
|
||
#include <GLFW/glfw3.h> | ||
#include <GLFW/emscripten_glfw3.h> | ||
#include <assert.h> | ||
|
||
// cpp otherwise it fails to link | ||
int main() { | ||
|
||
assert(glfwInit() == GLFW_TRUE); | ||
|
||
GLFWwindow* window = glfwCreateWindow(320, 200, "test_glfw3_port", 0, 0); | ||
assert(window != 0); | ||
// this call ensures that it uses the right port | ||
assert(emscripten_glfw_is_window_fullscreen(window) == EM_FALSE); | ||
glfwTerminate(); | ||
|
||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2941,6 +2941,8 @@ def run(linker_inputs, options, state, newargs): | |
logger.debug('stopping after linking to object file') | ||
return 0 | ||
|
||
phase_calculate_system_libraries(state, linker_arguments, newargs) | ||
|
||
js_syms = {} | ||
if (not settings.SIDE_MODULE or settings.ASYNCIFY) and not shared.SKIP_SUBPROCS: | ||
js_info = get_js_sym_info() | ||
|
@@ -2963,8 +2965,6 @@ def add_js_deps(sym): | |
settings.ASYNCIFY_IMPORTS_EXCEPT_JS_LIBS = settings.ASYNCIFY_IMPORTS[:] | ||
settings.ASYNCIFY_IMPORTS += ['*.' + x for x in js_info['asyncFuncs']] | ||
|
||
phase_calculate_system_libraries(state, linker_arguments, newargs) | ||
|
||
phase_link(linker_arguments, wasm_target, js_syms) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can revert this file since this will be part of the "port settings" PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No this has nothing to do with port settings. It is a change that is required for using js_libraries in ports |
||
|
||
# Special handling for when the user passed '-Wl,--version'. In this case the linker | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,13 +34,11 @@ | |
|
||
|
||
def load_port(name): | ||
expected_attrs = ['get', 'clear', 'show'] | ||
port = __import__(name, globals(), level=1) | ||
port = __import__(name, globals(), level=1, fromlist=[None]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does does the addition of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will double check if I can get away without it, but I copied this from your own PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I double checked and without Displaying If I use Asking Jetbrains AI give this answer (which I clipped because it is quite long but quite informative):
Note that documentation for |
||
ports.append(port) | ||
port.is_contrib = name.startswith('contrib.') | ||
port.name = name | ||
ports_by_name[port.name] = port | ||
for a in expected_attrs: | ||
assert hasattr(port, a), 'port %s is missing %s' % (port, a) | ||
if not hasattr(port, 'needed'): | ||
port.needed = lambda s: name in ports_needed | ||
else: | ||
|
@@ -57,13 +55,31 @@ def load_port(name): | |
if not hasattr(port, 'variants'): | ||
# port variants (default: no variants) | ||
port.variants = {} | ||
if not hasattr(port, 'show'): | ||
port.show = lambda: f'{port.name} (--use-port={port.name}; {port.LICENSE})' | ||
|
||
for variant, extra_settings in port.variants.items(): | ||
if variant in port_variants: | ||
utils.exit_with_error('duplicate port variant: %s' % variant) | ||
port_variants[variant] = (port.name, extra_settings) | ||
|
||
|
||
def validate_port(port): | ||
expected_attrs = ['get', 'clear', 'show'] | ||
if port.is_contrib: | ||
expected_attrs += ['URL', 'DESCRIPTION', 'LICENSE'] | ||
for a in expected_attrs: | ||
assert hasattr(port, a), 'port %s is missing %s' % (port, a) | ||
|
||
|
||
def validate_ports(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One reason I thought we might want to do this at runtime is that we might want to allow folks to drop in new ports (or maybe as you suggest using URL of a port on the command line). In that case it might be good to validate each time you use a port. However, we can address that once we get to that point. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Of course if/when ports are added dynamically or loaded on demand this would have to change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean technically you can do today by simply dropping a new file into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I reverted the change and now |
||
for port in ports: | ||
validate_port(port) | ||
for dep in port.deps: | ||
if dep not in ports_by_name: | ||
utils.exit_with_error('unknown dependency in port: %s' % dep) | ||
|
||
|
||
@ToolchainProfiler.profile() | ||
def read_ports(): | ||
for filename in os.listdir(ports_dir): | ||
|
@@ -72,10 +88,14 @@ def read_ports(): | |
filename = os.path.splitext(filename)[0] | ||
load_port(filename) | ||
|
||
for port in ports: | ||
for dep in port.deps: | ||
if dep not in ports_by_name: | ||
utils.exit_with_error('unknown dependency in port: %s' % dep) | ||
contrib_dir = os.path.join(ports_dir, 'contrib') | ||
for filename in os.listdir(contrib_dir): | ||
if not filename.endswith('.py') or filename == '__init__.py': | ||
continue | ||
filename = os.path.splitext(filename)[0] | ||
load_port('contrib.' + filename) | ||
|
||
validate_ports() | ||
|
||
|
||
def get_all_files_under(dirname): | ||
|
@@ -441,9 +461,15 @@ def add_cflags(args, settings): # noqa: U100 | |
|
||
|
||
def show_ports(): | ||
print('Available ports:') | ||
for port in sorted(ports, key=lambda p: p.name): | ||
print(' ', port.show()) | ||
sorted_ports = sorted(ports, key=lambda p: p.name) | ||
print('Available official ports:') | ||
for port in sorted_ports: | ||
if not port.is_contrib: | ||
print(' ', port.show()) | ||
print('Available contrib ports:') | ||
for port in sorted_ports: | ||
if port.is_contrib: | ||
print(' ', port.show()) | ||
|
||
|
||
read_ports() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
Emscripten "Contrib" Ports | ||
========================== | ||
|
||
Ports in this directory are contributed by the wider community and are | ||
supported on a "best effort" basis. Since they are not run as part of | ||
emscripten CI they are not always guaranteed to build or function. | ||
|
||
If you want to add a contrib port, please use another contrib port as | ||
an example. In particular, each contrib port must provide 3 extra piece | ||
of information: | ||
|
||
* `URL`: the url where the user can find more information about | ||
the project/port | ||
* `DESCRIPTION`: a (short) description of what the project/port | ||
is about | ||
* `LICENSE`: the license used by the project/port | ||
|
||
After adding a contrib port, you should consider modifying the documentation | ||
under `site/source/docs/compiling/Contrib-Ports.rst`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Copyright 2024 The Emscripten Authors. All rights reserved. | ||
# Emscripten is available under two separate licenses, the MIT license and the | ||
# University of Illinois/NCSA Open Source License. Both these licenses can be | ||
# found in the LICENSE file. | ||
|
||
import os | ||
|
||
TAG = '1.0.4' | ||
HASH = 'c3c96718e5d2b37df434a46c4a93ddfd9a768330d33f0d6ce2d08c139752894c2421cdd0fefb800fe41fafc2bbe58c8f22b8aa2849dc4fc6dde686037215cfad' | ||
|
||
# contrib port information (required) | ||
URL = 'https://github.com/pongasoft/emscripten-glfw' | ||
DESCRIPTION = 'This project is an emscripten port of glfw written in C++ for the web/webassembly platform' | ||
LICENSE = 'Apache 2.0 license' | ||
|
||
|
||
def get_lib_name(settings): | ||
return 'lib_contrib.glfw3.a' | ||
|
||
|
||
def get(ports, settings, shared): | ||
# get the port | ||
ports.fetch_project('contrib.glfw3', f'https://github.com/pongasoft/emscripten-glfw/releases/download/v{TAG}/emscripten-glfw3-{TAG}.zip', sha512hash=HASH) | ||
|
||
def create(final): | ||
root_path = os.path.join(ports.get_dir(), 'contrib.glfw3') | ||
source_path = os.path.join(root_path, 'src', 'cpp') | ||
source_include_paths = [os.path.join(root_path, 'external', 'GLFW'), os.path.join(root_path, 'include', 'GLFW')] | ||
for source_include_path in source_include_paths: | ||
ports.install_headers(source_include_path, target='GLFW') | ||
|
||
# this should be an option but better to disable for now... | ||
flags = ['-DEMSCRIPTEN_GLFW3_DISABLE_WARNING'] | ||
|
||
ports.build_port(source_path, final, 'contrib.glfw3', includes=source_include_paths, flags=flags) | ||
|
||
return [shared.cache.get_lib(get_lib_name(settings), create, what='port')] | ||
|
||
|
||
def clear(ports, settings, shared): | ||
shared.cache.erase_lib(get_lib_name(settings)) | ||
|
||
|
||
def linker_setup(ports, settings): | ||
root_path = os.path.join(ports.get_dir(), 'contrib.glfw3') | ||
source_js_path = os.path.join(root_path, 'src', 'js', 'lib_emscripten_glfw3.js') | ||
settings.JS_LIBRARIES += [source_js_path] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is never called as far as I can see? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it is used. My port has a javascript implementation. If you remove this then link fails because it cannot find all the functions implemented in js |
||
|
||
|
||
# Using contrib.glfw3 to avoid installing headers into top level include path | ||
# so that we don't conflict with the builtin GLFW headers that emscripten | ||
# includes | ||
def process_args(ports): | ||
return ['-isystem', ports.get_include_dir('contrib.glfw3')] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we want the include path to include Perhaps add a comment such as:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok that makes sense |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this header any different the emscirpten one?
If not perhaps we could just install
emscripten_glfw3.h
and rely on the existing header?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if this it is the same or not. But the idea is that the port is self contained and brings its own dependencies. If it were to diverge then that would become an issue. I would rather keep it that way. Note that this
test_contrib_ports.cpp
will be replaced with another port once there is another one (when/if I work on libarchive I will switch it to this port)