Skip to content
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

Batch file to mimic 'make' on Windows #61099

Closed
zware opened this issue Jan 8, 2013 · 21 comments
Closed

Batch file to mimic 'make' on Windows #61099

zware opened this issue Jan 8, 2013 · 21 comments
Assignees
Labels
build The build process and cross-build OS-windows type-feature A feature request or enhancement

Comments

@zware
Copy link
Member

zware commented Jan 8, 2013

BPO 16895
Nosy @terryjreedy, @tjguk, @jkloth, @zware, @zooba
Files
  • Make.bat: Mimic 'make' on Windows
  • win_make.diff: Patch to add make.bat
  • win_configure-make.diff: Updated patch
  • win_configure-make.v2.diff: Version 2
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/zware'
    closed_at = <Date 2014-07-14.21:08:47.492>
    created_at = <Date 2013-01-08.20:43:41.179>
    labels = ['type-feature', 'OS-windows', 'build']
    title = "Batch file to mimic 'make' on Windows"
    updated_at = <Date 2014-07-14.21:08:47.490>
    user = 'https://github.com/zware'

    bugs.python.org fields:

    activity = <Date 2014-07-14.21:08:47.490>
    actor = 'zach.ware'
    assignee = 'zach.ware'
    closed = True
    closed_date = <Date 2014-07-14.21:08:47.492>
    closer = 'zach.ware'
    components = ['Build', 'Windows']
    creation = <Date 2013-01-08.20:43:41.179>
    creator = 'zach.ware'
    dependencies = []
    files = ['28632', '29363', '29667', '30351']
    hgrepos = []
    issue_num = 16895
    keywords = ['patch']
    message_count = 21.0
    messages = ['179369', '183843', '183868', '183879', '183886', '183890', '183903', '183904', '183907', '185934', '186201', '186318', '189875', '190241', '190242', '190244', '190247', '190248', '190249', '222889', '223060']
    nosy_count = 7.0
    nosy_names = ['terry.reedy', 'tim.golden', 'jkloth', 'BreamoreBoy', 'sbt', 'zach.ware', 'steve.dower']
    pr_nums = []
    priority = 'normal'
    resolution = 'postponed'
    stage = None
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue16895'
    versions = ['Python 3.5']

    @zware
    Copy link
    Member Author

    zware commented Jan 8, 2013

    I find myself frustrated with some of the hoops I have to jump through and extra things I have to remember when I want to play around with Python on Windows. To make things a little easier, I've created a 'make.bat' file that can sit in the root of the repository and do a few of the more common tasks:

    make [build] [-64] -- Runs Tools\buildbot\build[-amd64].bat
    make clean [-64] -- Runs Tools\buildbot\clean[-amd64].bat
    make doc [args] -- Runs Doc\make.bat [args] with %PYTHON% set to 'py.exe -2'
    make patchcheck -- Runs Tools\scripts\patchcheck.py
    make test [test args] -- Runs the test suite with passed arguments

    It seems to work pretty well for me and I think it could be very useful to others, particularly new contributors. I'm sure there's plenty of room for improvement, though :)

    I don't know if this script might interfere or conflict with Cygwin or other tools; if so and it were decided to include this file, it could easily be renamed to 'wmake.bat' or some such.

    Hope this is useful enough to include, or at least useful to someone else :)

    @zware zware added OS-windows type-feature A feature request or enhancement labels Jan 8, 2013
    @terryjreedy
    Copy link
    Member

    +1

    Add make external[-64] to runs Tools/buildbot/external[-amd64].bat
    and explain this in the devguide (if not already) rather than buried in the opaque PCBuild/readme.

    Even after reading build.bat, I do not understand what is the different net effect of that versus just double clicking pcbuild.sln and building. So some explanation in the devguide would be needed.

    @zware
    Copy link
    Member Author

    zware commented Mar 10, 2013

    Here's an updated version in the form of a patch.

    Features include:

    • Ensure things are done in the right directory with pushd/popd

    • Allow setting environment variables (for the life of the script) with:
      make test "PYTHON=..\PCbuild\python.exe"

    • Emulate UNIX's make -C <dir> (cd dir; call make.bat %*, essentially)

    • Choose x86 or x64 with "-64" command line switch

    • Intelligently choose an interpreter for make patchcheck and make test

    • Available targets are: build, clean, patchcheck, ready, test. "ready" is implemented by Tools/buildbot/external[-amd64].bat; "make ready" sounds better and possibly more accurate than "make external" to me.

    • Create a convenience "python.bat" script, which calls the newly built interpreter with all supplied arguments. Created by :build, deleted by :clean (and added to .hgignore)

    Everything seems to work ok for me, but my testing platforms are limited to a single Win7 laptop, currently. This issue is also somewhat constrained by bpo-17202; it is supposed to work without any change to .hgeol, but that can't be guaranteed.

    @sbt
    Copy link
    Mannequin

    sbt mannequin commented Mar 10, 2013

    +1

    To use Tools/builbot/*.bat doesn't the current directory have to be the main directory of the repository? Then I see no point in the "-C" argument: just set the correct directory automatically.

    I think make.bat should also support creation of non-debug builds. (Maybe have targets "release" and "debug"?)

    Tools/buildbot/build.bat already calls external.bat and clean.bat. This currently makes the "ready" target unnecessary. However, I don't think build should be calling clean.bat (or external.bat). Perhaps you should just inline the necessary parts of Tools/buildbot/build.bat.

    @zware
    Copy link
    Member Author

    zware commented Mar 10, 2013

    Richard Oudkerk added the comment:

    +1
    Thank you :)

    To use Tools/builbot/*.bat doesn't the current directory have to be the main directory of the repository? Then I see no point in the "-C" argument: just set the correct directory automatically.

    That is true, and it does already automatically set the correct
    directory. The point of the -C option is for Doc/make.bat--from the
    root dir, call "make -C Doc html", and make cd's into Doc, and there
    calls "make.bat html", and the html docs are made. I didn't just
    hardwire the option to "-C Doc" even though that's the only place that
    can use -C, just in case there is someday another make.bat floating
    around the repository. The original version I posted just had a "doc"
    target that called Doc/make.bat with supplied arguments, but forcing
    the use of the UNIXy command makes documenting how to do things
    easier: just one command on all platforms.

    I think make.bat should also support creation of non-debug builds. (Maybe have targets "release" and "debug"?)

    I agree. I've had a thought for this; what about adding a
    "configure.bat" that takes a few of the applicable options from the
    UNIX "configure" script, and sets some environment variables (and/or
    writes out a "win-config.dat") for make.bat's use?

    Tools/buildbot/build*.bat already calls external.bat and clean.bat. This currently makes the "ready" target unnecessary.

    I thought the same initially, but I realized that it is useful for
    building using the VS GUI--clone the repo, call "make ready", then
    open pcbuild.sln in Visual Studio and you're ready to build everything
    there.

    However, I don't think build should be calling clean.bat (or external.bat). Perhaps you should just inline the necessary parts of Tools/buildbot/build*.bat.

    I've thought about this too, and am thinking that it would make a
    certain amount of sense to inline the entirety of Tools/buildbot.
    Make everything possible from just make.bat, and eventually migrate
    the buildbots to use it, and then the Tools/buildbot directory can go
    away alltogether. This would also make doing release vs debug easier.

    @terryjreedy
    Copy link
    Member

    One must run external.bat if one is to subsequently build from the vs gui with *most* of the external dependencies. I think the command to run it should be 'external', not 'ready'. 'External' means get the external dependencies and anyone who has run external.bat will know what it means. 'Ready' does not mean anything in particular.

    Just curious:
    Why do the buildbots run make clean before re-compiling? I seems like lots of extra work to re-compile things that are up to date?

    What does running 'kill-python before re-building python do? I have not seen it mentioned in the in the devguide or pcbuild/readme.

    @zware
    Copy link
    Member Author

    zware commented Mar 10, 2013

    Terry J. Reedy added the comment:

    One must run external.bat if one is to subsequently build from the vs
    gui with *most* of the external dependencies. I think the command to
    run it should be 'external', not 'ready'. 'External' means get the
    external dependencies and anyone who has run external.bat will know
    what it means. 'Ready' does not mean anything in particular.

    Fair point. Thinking about it again after some sleep, I agree. Next version will revert to 'external' rather than 'ready'.

    Just curious:
    Why do the buildbots run make clean before re-compiling? I seems like
    lots of extra work to re-compile things that are up to date?

    I think the idea is to make sure everything is fresh, and avoid phantom problems from things that shouldn't cause problems, but do.

    What does running 'kill-python before re-building python do? I have not
    seen it mentioned in the in the devguide or pcbuild/readme.

    I believe it's what actually performs the cleaning process. Tools/buildbot/clean.bat builds kill_python.exe and then runs it.

    @sbt
    Copy link
    Mannequin

    sbt mannequin commented Mar 11, 2013

    What does running 'kill-python before re-building python do? I have not
    seen it mentioned in the in the devguide or pcbuild/readme.

    It kills any currently running python(_d).exe processes. This is because Windows does not allow program or library files to be removed or overwritten while they are being used, potentially causing compilation failures.

    @terryjreedy
    Copy link
    Member

    Thanks, clean and kill make sense for unattended build-bots. For interactive use, when 2 minutes rebuilding is a big deal, clean is a last resort. Let's just make sure we do not somehow suggest that it needs to be done routinely. Or to put it another way, do document that 'build' is intended for fail-safer unattended buildbots and not necessarily for interactive human use. And also that kill does what a human would normally do by closing windows on the task bar, or, as a last resort, with task manager.

    @zware
    Copy link
    Member Author

    zware commented Apr 3, 2013

    I was rather off about kill_python, wasn't I?

    Anyway, I've finally gotten another version put together that I'd like to get comments on. Major differences between this patch and the previous one, in no particular order:

    • Add a 'configure.bat' script to increase the parallel with Unix building. Currently only has 2 options, --with-pydebug and --with(out)-64-bit, which affect how PY_PLATFORM and PY_CONFIGURATION are set in make.bat, which allows for building any combination of Debug, Release, 32 bit, and 64 bit with make.bat.

    • Add 'win-config.dat' to .hgignore; this file stores configure.bat's options for make.bat's use.

    • Update documentation: PCbuild/readme.txt gets significant updates, including some that apply without make.bat and which I can split out into a separate patch if someone wants to commit those separately. Doc/using/windows.rst also gets a small update which actually just goes with one of the PCbuild/readme.txt updates and isn't affected by make.bat.

    • make.bat is now stand-alone; it does not rely on any other batch scripts except configure.bat (namely Tools/buildbot/*).

    • Renamed "ready" target to "external", as promised.

    • Reimplemented "test" target to match the Unix implementation. Also added "buildbottest" target, which matches Unix implementation.

    • Added separate "tcltk" target to build tcltk and copy the built .dlls to the appropriate place for the built Python to find them.

    • Added "all" alias to "build" target (to match Unix). "build" calls :external on its own, and calls :tcltk if it can't find the appropriate tcl/tk .dlls.

    • Added "clobber" target, which does its best to obliterate everything make.bat can create. The only way I've thought of to be more thorough is to actually delete the entire contents of the PCbuild directory and do an hg revert -C PCbuild to get it back, but that does have the possibility to be more destructive than desired.

    • Added variables to the top of the file to set the versions of the external projects. This means there's only one place to update when an external is updated, and for easy testing one could do something akin to make "OPENSSLVERSION=openssl-1.0.1e"

    • Added "msi" target to perform the task of Tools/buildbot/buildmsi.bat. Note that this one is hard for me to test, as buildmsi.bat does not work properly for me. However, the msi target works as well or better than buildmsi.bat for me, and should work assuming msi.py can do what it is meant to. I wonder, though; does anybody use buildmsi.bat? I noticed that it has information in it hard-coded for Python 2.6a3...

    Several things have gone through an iteration or two since the last patch; I'll try to go through and add some comments on Rietveld myself.

    Since make.bat is now stand-alone, if it is accepted (and it is deemed desirable to do so), the Windows buildbots could be converted to use make.bat instead of Tools/buildbot/*, and that directory could actually be removed. This would also make it easy to set up a buildbot that tests a Release configuration of Python.

    All comments welcome :)

    @sbt
    Copy link
    Mannequin

    sbt mannequin commented Apr 7, 2013

    You seem to end your subroutines (or whatever they are called) using "goto end" rather than "exit /b". Since popd follows the "end" label, does this mean that you get a popd after calling each subroutine? Is this intended and can it cause unmatched pushd/popd-s?

    (I am not familiar with writing batch files.)

    Also, I think 32 bit builds should be the default. Many people with 64 bit Windows are using Visual Studio Express which only has 32 bit support.

    @zware
    Copy link
    Member Author

    zware commented Apr 8, 2013

    You seem to end your subroutines (or whatever they are called) using "goto end" rather than "exit /b". Since popd follows the "end" label, does this mean that you get a popd after calling each subroutine?

    Yes.

    Is this intended and can it cause unmatched pushd/popd-s?

    It is intended and it can, but so far I haven't run into any trouble
    with it. However, I have realized that I haven't done any testing
    with some pushd's already on the stack... I'll do some more looking
    into that, and may have to implement either some form of callback
    labels or counting pushd's to properly popd.

    (I am not familiar with writing batch files.)

    Also, I think 32 bit builds should be the default. Many people with 64 bit Windows are using Visual Studio Express which only has 32 bit support.

    Fair point. I suppose I had been assuming that the error message from
    not finding the proper vcvars*.bat file would be an indication to pass
    '--without-64-bit' to configure.bat, but it is much nicer to just fall
    back to 32 bit. Also, it would be nice to just implode from the start
    if there is no compiler available. Next version of the patch will do
    both of these things in configure.bat; quit with an error message if
    %VS100COMNTOOLS% is not defined, and check for the existence of
    %VS100COMNTOOLS%\..\..\VC\bin\x86_amd64\vcvarsx86_amd64.bat before
    setting %PY_PLATFORM% to x64.

    Thanks for the comments.

    @zware
    Copy link
    Member Author

    zware commented May 23, 2013

    Here's a new version of the patch, which is a major rewrite. Among the changes:

    • Switch from using 'goto' to execute the right subroutine to 'call' and end every subroutine with 'exit /B' (thank you Richard for making me aware of that possibility). This makes the :end label useless, so it's removed. Every subroutine now expects to start in the root of the source tree, and is expected to return there before exiting.

    • Changed the argument parsing magic to a different flavor of magic. Setting variables on the command line is now much more like it is using Unix make, no more required double quotes around the whole assignment, and you can now specify multiple targets in a single command. This method can be quite a bit slower if you give a huge command, as it steps through the command line a character at a time (on the order of several seconds if you're appending something to PATH, for instance. The delay is not noticeable if you're just giving targets), but at least all the magic is self-contained.

    • Add '--no-externals' and '--interactive' options to configure.bat to ignore the presence or absence of the external libs and to allow questions to be asked of the user, respectively. I've waffled back and forth on whether it is better for the '--interactive' option to be on or off by default, currently it is off.

    • On 64 bit machines, default to Win32 platform if vcvarsx86_amd64.bat can't be found.

    • Give some nicer output just about everywhere. This includes making configure.bat die early in case %VS100COMNTOOLS% is not defined with a message to install MSVC++ 2010 Express, a warning if NASM is not available, and tagging all output with the name of the script. Also, add a message at the end of building Python giving the best estimate of the outcome.

    • Another part of giving a nice message at the end of building Python: if the expected executable file exists at the end, exit code 0 is returned. This is for the buildbots, so that even if the build had errors, the tests are still run so we can see what is actually broken. This ties in with the new '--no-externals' option on configure.bat, which would allow a buildbot to build with '--no-externals' and still be able to test everything else.

    • List and use specific exit codes. If anyone has advice on better numbers to use (more standard numbers, perhaps), please let me know :).

    • Use "absolute relative" paths (paths that always start with %~dp0, but may include '..') to avoid some directory changing magic just to make a relative path point to the right place.

    • 'clobber' target builds the clean target of Win32 configuration, then x64 config if the environment can be set up to do so.

    • 'importlib' will clean up after itself if there wasn't a build already done.

    • Some refactoring and cleanup to put things in places that make more sense and look better. This includes major changes to :external and :tcltk to use a couple of loops to be more DRY.

    • Change Tools/scripts/run_tests.py (used by the test targets in make.bat and Makefile) to use subprocess.call instead of os.execv on win32. Since execv creates a new process on Windows, control was handed back to the console as soon as the execv call was made, but the test output still came to the terminal so the prompt was lost in the test output and did not automatically come up at the end of the test. Using subprocess.call keeps control in the parent python(_d) process and doesn't release back to the console until the test is done.

    • Added better documentation of make.bat usage to PCbuild\readme.txt, and took out unrelated changes to that file (which will be posted to another issue).

    Everything works as expected for me, but I do only have a 32bit machine available to me currently. I hope to be able to test on a 64bit machine soon, but have no guarantees. For anyone testing this, I would suggest to run the command "prompt $+%PROMPT%" before testing; this will add a "+" to the beginning of your prompt for every dir on the pushd/popd stack. Neither configure.bat nor make.bat should ever remove dirs from that stack, and should not leave any extras when they're done (unless forcibly killed in the middle of running).

    @sbt
    Copy link
    Mannequin

    sbt mannequin commented May 28, 2013

    I can't say I know enough about batch files to understand much of the code, but a few notes:

    Windows XP does not have the command "where" which you use -- Python 3.4 will still support XP.

    Except perhaps for looping I would prefer to get rid of the use of goto. The fact that some goto targets end in "exit /b ..." make it very confusing as to where "exit /b" will return control.

    The initial pushd is matched by various popd's which are scattered over hundreds of lines (including one in :usage). I think it would be better to keep matching pushd/popd reasonably close together. For instance, I think you could do something like

    ...
    pushd "%~dp0"
    call :main ...
    popd
    exit /b
    
    :main
    ...
    exit /b
    

    It would also be helpful if the end of the subroutines were marked with a comment like

    rem end :foo
    

    @briancurtin
    Copy link
    Member

    Can't this just be a Python script?

    @sbt
    Copy link
    Mannequin

    sbt mannequin commented May 28, 2013

    Can't this just be a Python script?

    That would cause bootstrap issues for people who do not already have
    python installed.

    @zware
    Copy link
    Member Author

    zware commented May 28, 2013

    Richard Oudkerk added the comment:

    I can't say I know enough about batch files to understand much of the code, but a few notes:

    Windows XP does not have the command "where" which you use -- Python 3.4 will still support XP.

    Oh, that is an issue. I don't have an XP machine to test on anymore,
    thank you for that catch. I found a workaround on StackOverflow that
    looks short enough to be usable instead.

    Except perhaps for looping I would prefer to get rid of the use of goto. The fact that some goto targets end in "exit /b ..." make it very confusing as to where "exit /b" will return control.

    The only goto's that are not part of loops are now one near the
    beginning for the -C option, in the target validation routine to show
    the usage message and die, and in a couple of routines which use "goto
    no-configure" to show a common message and die. I'd rather not have
    to copy that message every place it is used, but that is an option.
    Would just adding comments explaining where execution is going and
    whether it is coming back be sufficient?

    The initial pushd is matched by various popd's which are scattered over hundreds of lines (including one in :usage). I think it would be better to keep matching pushd/popd reasonably close together. For instance, I think you could do something like

    ...
    pushd "%~dp0"
    call :main ...
    popd
    exit /b
    
    :main
    ...
    exit /b
    

    Fair enough, I can change that. I tried to keep the matches to the
    initial pushd to a minimum, but perhaps there are a couple more I can
    eliminate.

    It would also be helpful if the end of the subroutines were marked with a comment like

    rem end :foo
    

    Easy enough, consider it done :)

    @briancurtin
    Copy link
    Member

    Don't we already require an existing Python to build some of the third-party stuff, e.g., OpenSSL?

    I don't think the bootstrapping issue holds that much weight. Adding some huge batch script that maybe one or two people even know how to modify is a much higher cost than just having someone install Python.

    @zware
    Copy link
    Member Author

    zware commented May 28, 2013

    Brian Curtin added the comment:

    Don't we already require an existing Python to build some of the third-party stuff, e.g., OpenSSL?

    Only for building a 64-bit Python on 32-bit Windows. Otherwise,
    OpenSSL is built using the just-built interpreter.

    I don't think the bootstrapping issue holds that much weight. Adding some huge batch script that maybe one or two people even know how to modify is a much higher cost than just having someone install Python.

    Fair enough, but even when Python is installed, there's still the
    issue of whether it will be findable on PATH, whether .py is in
    PATHEXT, what version of Python is installed (and which one is on
    PATH), etc. etc...

    However, you've made me think; perhaps configure.bat could build a
    minimal Python that can then be used for a make.py. I'll do some
    experimenting and see what I can come up with.

    @BreamoreBoy
    Copy link
    Mannequin

    BreamoreBoy mannequin commented Jul 12, 2014

    Is this still relevant or has it been overtaken by other work from Zach or Steve?

    @zware
    Copy link
    Member Author

    zware commented Jul 14, 2014

    Still relevant, but the current patch is overkill (Brian was right, it's just way more batch than is healthy to check in). Things are changing rapidly, though; I'll close it as "postponed" for now, with the expectation of reopening someday.

    @zware zware added the build The build process and cross-build label Jul 14, 2014
    @zware zware closed this as completed Jul 14, 2014
    @zware zware self-assigned this Jul 14, 2014
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    build The build process and cross-build OS-windows type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants