Skip to content

Conversation

@saschanaz
Copy link
Collaborator

@saschanaz saschanaz commented Dec 22, 2017

Replaces #5955

This PR:

  1. introduces EMSCRIPTEN_ALLOW_NEWER_PYTHON to allow Python 3
  2. creates force_python_version.py to conditionally force Python 2
  3. separates colored logger as colored_logger.py
  4. uses emcc.py instead of emcc internally
  5. adds a test
  6. lets CircleCI test on Python 3 while Travis still tests on Python 2

em++ Outdated
if __name__ == '__main__':
sys.exit(subprocess.call(['python2', os.path.join(os.path.dirname(os.path.realpath(__file__)), 'emcc.py')] + sys.argv[1:]))
emcc = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'emcc')
if __name__ == '__main__' and not force_python_version.run(emcc):
Copy link
Member

Choose a reason for hiding this comment

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

This line reads unclearly to me. It seems odd that the check for __main__ is related to a check for the python version, and also it's a little surprising that force_python_version returns a result saying whether it ran the command or not.

Could force_python_version call sys.exit to quit, if it ran the command? Then we could just call it inside an if on __main__ as a command, not a condition, that might be clearer?

Copy link
Member

Choose a reason for hiding this comment

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

(Otherwise I think this PR is good!)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Could force_python_version call sys.exit to quit, if it ran the command?

Actually it already does, and I just updated force_python_version to also automate import emcc; emcc.run().

@saschanaz
Copy link
Collaborator Author

saschanaz commented Dec 25, 2017

test_merge_pair randomly fails and I have no idea why...

@saschanaz
Copy link
Collaborator Author

Turns out that apply_funcs_map in asm_module.py assumes self.funcs is ordered but actually not.

https://github.com/kripken/emscripten/blob/c5a455873a5ee84ac07961e06a3a58204e5813b2/tools/asm_module.py#L312

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

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

Nice work here!

One more comment, we should measure that these changes don't affect build times. It seems like it shouldn't - same amount of imports/subprocess invocations - but still. Seeing how fast libc or zlib are build, for example.

if has:
print(' checking emcc...')
check_execute([python, EMCC, '--version'])
check_execute([python, EMCC[:-3], '--version'])
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't it work with or without .py? Maybe I don't remember why the test checks the .py version later...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it works with or without it. I did this because the test specifically wants to test emcc.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Could this be a def remove_py_suffix() function or similar that looks for .py at the end and removes that? This could be a bit brittle otherwise for future refactors in mind, if one unconditionally just removes three last chars here?

import subprocess
return subprocess.run(py2 + [os.path.realpath(filename) + '.py'] + sys.argv[1:]).returncode

def allowed_version():
Copy link
Member

Choose a reason for hiding this comment

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

how about is_allowed_version, since this checks it, and doesn't return the allowed version?

@@ -0,0 +1,43 @@
'''
Copy link
Member

Choose a reason for hiding this comment

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

how about calling this just python_version, or python_version_handling or something like that, since it also provides utilities to check it etc.?

EMCC = path_from_root('emcc')
EMXX = path_from_root('em++')
EMAR = path_from_root('emar')
EMCC = path_from_root('emcc.py')
Copy link
Member

Choose a reason for hiding this comment

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

why, and why these three (and not emranlib just below etc.)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  1. Calling emcc recursively will cause multiple duplicated Python version warnings
  2. There are many tests that call [PYTHON, EMCC] and expect empty stderr output. A Python version warning will break all of them.

The version warning occurs only on emcc wrapper so this change will remove the problems.

emranlib is just a no-op, em-config already allows Python 3, so no need to change. (Do we want it to require Python 2?)

if env.get(dangerous) and env.get(dangerous) == non_native.get(dangerous):
del env[dangerous] # better to delete it than leave it, as the non-native one is definitely wrong
return env
env['CC'] = quote(EMCC) if not WINDOWS else 'python %s' % quote(EMCC)
Copy link
Member

Choose a reason for hiding this comment

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

why?

Copy link
Collaborator Author

@saschanaz saschanaz Jan 3, 2018

Choose a reason for hiding this comment

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

  1. Calling emcc internally will cause multiple duplicated Python version warnings
  2. I think they are anyway equivalent, is there a specific need to do this conditionally?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, hopefully we don't need the conditional stuff. @juj, was it working around a windows issue?

Copy link
Member

Choose a reason for hiding this comment

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

I think it's safe to do this, as we should be calling [PYTHON, EMCC] anyhow everywhere, including windows.

Copy link
Collaborator

Choose a reason for hiding this comment

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

On Windows it's not possible to invoke /path/to/emscripten/emcc when emcc is a python script. (there's no concept of reading a shebang from the file on Windows), but one always needs to do python /path/to/emscripten/emcc to run the Python script.

That's why we have the emcc.bat file on Windows. If one invokes the subprocess with "shell expansion" enabled, then /path/to/emscripten/emcc works, and looks up /path/to/emscripten/emcc.bat. However shell expansion is sometimes considered poor form in subprocess invocations, which is why we'd prefer to disable shell expansion when invoking, and explicitly call the batch file /path/to/emscripten/emcc.bat.

To summarize, on Windows

subprocess.run(['c:/emscripten/emcc`]) # Fails, emcc is a py script, can't execute
subprocess.run(['c:/emscripten/emcc.py`]) # Fails, emcc.py is a py script, can't execute
subprocess.run(['c:/emscripten/emcc.py`], shell=True) # Fails, emcc.py is a py script, can't execute
subprocess.run(['c:/emscripten/emcc`], shell=True) # Works, and invokes emcc.bat
subprocess.run(['c:/emscripten/emcc.bat`], shell=True) # Works, and invokes emcc.bat

subprocess.run(['c:/emscripten/emcc.bat`]) # Works, and invokes emcc.bat, preferred
subprocess.run(['python', 'c:/emscripten/emcc`]) # Works, and invokes emcc python script, slightly more preferred compared to the .bat script to avoid py -> batch -> py roundtripping
subprocess.run(['python', 'c:/emscripten/emcc.py`]) # Works, and invokes emcc.py script, slightly more preferred compared to the .bat script to avoid py -> batch -> py roundtripping

We prefer to avoid shell=True whenever possible, since it expands PATHs, %s and possibly $s depending on the calling terminal (PowerShell, MinGW, CygWin, MSYS). Since we're already being explicit with the path where emcc executable resides, it's nicer to explicitly say "emcc.bat is here on this absolute path, call this one", or "run this py script on python".

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for great explanation! Yes, we need to explicitly call python on Windows, by is there a specific need to do this conditionally I meant that we can also do same thing on non-Windows: env['CC'] = 'python %s' % quote(EMCC)

I should have been clearer, sorry.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh right, I see now I kind of was explaining a separate issue. Yeah, the original adjustment was about bff4d2b, and I agree that it should also work on non-Windows, so this change is good.

@saschanaz
Copy link
Collaborator Author

I tried renaming force_python_version to python_selector as python_version.run() looks unintuitive to me. What do you think?

@kripken
Copy link
Member

kripken commented Jan 4, 2018

I prefer the new names (python_selector, on_correct_version), but just a matter of opinion I guess. @juj, what do you think?

@juj
Copy link
Collaborator

juj commented Jan 5, 2018

I like python_selector as a name much better as well rather than force_python_version, since the name force always reads a bit like a "patched this override after the fact on someone else's code" flow.

@juj
Copy link
Collaborator

juj commented Jan 10, 2018

This PR looks good to merge to me now, any remaining concerns? Were there still any random test failures?

@saschanaz
Copy link
Collaborator Author

I'm not seeing any random failures now, I think it's safe to merge.

@kripken kripken merged commit f067c2a into emscripten-core:incoming Jan 11, 2018
@kripken
Copy link
Member

kripken commented Jan 11, 2018

@saschanaz , great work here and in all the PRs with Python3 support leading to here :)

@cpitclaudel
Copy link

Thanks for the great work! But this broke some of my builds :/ (I just updated to 1.37.36).

The problem is this part of get_building_env:

    env['CC'] = 'python %s' % quote(EMCC)
    env['CXX'] = 'python %s' % quote(EMXX)
    env['AR'] = 'python %s' % quote(EMAR)
    env['LD'] = 'python %s' % quote(EMCC)

This used to just point to EMCC, EMAR, etc. The change causes some configure scripts to choke as they detect tools: they call which "python /vagrant/z3-js/emsdk-portable/emscripten/1.37.36/emar.py" to check for the appropriate binary, and promptly fail. (The particular case where I'm seeing this is Z3).

@kripken
Copy link
Member

kripken commented Mar 25, 2018

Thanks @cpitclaudel for the bug report. Can you please open a new issue for that, with a testcase showing the failure? (would be very helpful if you can extract the relevant part of the Z3 configure script for that, then we can use it in testing)

@cpitclaudel
Copy link

Sure, with pleasure :) #6378

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants