[ci skip] Add note that this change may break SetOption() + ninja usage with fix
[scons.git] / CONTRIBUTING.rst
blobf255e00a1e9c83a724cd801e2ec39f0db4f988cf
1 Contributing to SCons
2 #####################
4 Introduction
5 ============
7 Thanks for taking the time to contribute to SCons!
9 This will give a brief overview of the development process,
10 and about the SCons tree (right here, if you're reading this
11 in Github, or in a cloned repository).
13 There are lots of places we could use help - please don't
14 think we're only interested in contributions to code.
16 If you're going to contribute, we'd love to get to know you
17 a bit and understand and what problems you're looking to solve,
18 or what you are intending to improve, whether that's documentation,
19 code, examples, tutorials, etc. A great way to introduce yourself is to
20 to hop onto the `SCons Discord Server <https://discord.gg/bXVpWAy>`_
21 to chat.  You don't have to be a regular Discord user,
22 there is a web interface.
24 Resources
25 =========
27 Here are some important pointers to other resources:
29   * `SCons Home Page <https://scons.org>`_
30   * `Github Project Page <https://github.com/scons/scons>`_
31   * `Bugs and Feature Requests <https://scons.org/bugs.html>`_
32   * `Development <https://scons.org/dev.html>`_
33   * `SCons Developer's Guidelines <https://scons.org/guidelines.html>`_
34   * `Contacts <(https://scons.org/contact.html>`_
36 Reporting Bugs
37 ==============
39 One of the easiest ways to contribute is by filing bugs.
40 The SCons project welcomes bug reports and feature requests,
41 but we *do* have a preference for having talked about them first -
42 we request you send an email to the
43 `SCons Users Mailing List <https://pairlist4.pair.net/mailman/listinfo/scons-users>`_
44 or hop on the Discord channel (see link above), and if so
45 instructed, then proceed to an issue report.
47 You can explore the list of existing bugs on GitHub.
48 Sometimes there's work in progress which may include temporary
49 workarounds for the problem you've run into::
51     https://github.com/SCons/scons/issues
54 About the Development Tree
55 ==========================
57 This tree contains a lot more than just the SCons engine itself.
58 Some of it has to do with packaging it in a couple
59 of forms: a Python-installable package (source distribution
60 and installable wheel file, which get uploaded to the Python
61 Package Index), a portable zip (or tar) distribution
62 called "scons-local", and a full source bundle.  You usually
63 don't need to worry about the packaging parts when working
64 on a source or doc contribution - unless you're adding an entirely
65 new file, then the packaging bits may need to know about it. The
66 project maintainers can usually help with that part.
67 There are also tests and tools in the tree.
69 The *full* development cycle is not just to test code changes directly,
70 but also to package SCons, unpack the package, install SCons in a test
71 location, and then run the tests against the unpacked and installed
72 software.  This helps eliminate problems caused by the development
73 tree being different than the tree anyone else would see (files
74 not checked in to git, files not added to package manifest, etc.)
75 Most of that is handled by the CI setup driven through GitHub,
76 which runs checks for each update to a Pull Request.
78 For just working on making an individual change to the SCons source, however,
79 you don't actually need to build or install SCons; you just edit and
80 execute SCons in-place.  See the following sections below for more
81 information:
83     `Making Changes`_
84         How to edit and execute SCons in-place.
86     `Debugging`_
87         Tips for debugging problems in SCons.
89     `Testing`_
90         How to use the automated regression tests.
92     `Typical Development Workflow`_
93         An example of how to put the edit/execute/test pieces
94         together in a reasonable development workflow.
97 Executing SCons Without Installing
98 ==================================
100 Since SCons is written entirely in Python, you don't have to "build"
101 SCons to run it. "Building" refers to the steps taken to prepare
102 for constructing packages, the most time-consuing of which is
103 building the documentation.
105 Documentation is written in a markup language which is a
106 light extension of Docbook-XML, and the doc build consists
107 of translating to pure docbook, then using standard tools to
108 generate HTML and PDF outputs from that. There's lots more
109 on the documentation process at the Documentation Toolchain page:
111     https://github.com/SCons/scons/blob/master/doc/overview.rst
114 You can execute SCons directly from this repository. For Linux or UNIX::
116     $ python scripts/scons.py [arguments]
118 Or on Windows::
120     C:\scons>py scripts\scons.py [arguments]
122 If you run SCons this way, it will read the ``SConstruct`` file in this repo,
123 which will build and package SCons itself, which you probably don't want
124 unless you are doing development that relates to the packaging.
126 Often when doing SCons development, you have a sample project that
127 isn't working right, and it's useful to be able to build that
128 project from the place you're working on changes to SCons. You
129 can do that with the ``C`` (change directory) option::
131     $ python scripts/scons.py -C /some/other/location [arguments]
133 There is another approach that kind of reverses that order:
134 construct a Python virtualenv and install the development tree in it.
135 If you're not familiar with virtualenvs, there's an example here:
137     https://scons-cookbook.readthedocs.io/en/latest/#setting-up-a-python-virtualenv-for-scons
139 Follow the initial steps, except omit installing ``scons`` as a package.
140 When the virtualenv is contructed and activated, go to your working SCons
141 git tree and perform a development install instead::
143     (myvenv) $ pip install --editable .
145 Now while this virtualenv is activated, the command ``scons`` will refer
146 to this editable version, and you don't have to be "in" this tree
147 to run it.
149 You can also arrange to execute ``scons.py`` from the command line
150 by adding it to the ``PATH``, like::
152     # on Linux/Mac
153     $ export PATH=$PATH:`pwd`/scripts
155     # on Windows
156     C:\> set PATH="%PATH%;C:\path\to\scripts"
158 Be careful on Windows, the path has a limit of 1024 characters which
159 is pretty easy to exceed, and it will just truncate.
161 You may first need to make ``scons.py`` executable (it should be
162 by default, but sometimes things happen)::
164     $ chmod +x scripts/scons.py
167 Other Required Software
168 =======================
170 Running SCons has no installation dependencies beyond a compatible version
171 of Python. The tools which will be used to to actually construct the
172 project, such as compilers, documentation production tools, etc.
173 should of course be installed by the appropriate means.  In order
174 to develop SCons and run its test suite, there are some dependencies,
175 listed in the ``requirements-dev.txt`` file. Install these with::
177     $ python -m pip install -r requirements-dev.txt
179 For building the SCons packages and documentation there are some further
180 requirements, you can get these with::
182     $ python -m pip install -r requirements-pkg.txt
184 The requirements are inclusive so you only need the latter to get
185 everything installed.
187 There are other, non-Python requirements to do a doc build. These
188 are system-specific. See bin/scons_dev_master.py for the set up that
189 works for Ubuntu systems.
192 Making Changes
193 ==============
195 Virtually all of the SCons functionality exists in the "build engine," the
196 ``SCons`` subdirectory hierarchy that contains all of the modules that
197 make up SCons.  The ``scripts/scons.py`` wrapper script exists mainly to find
198 the appropriate build engine module and execute it.
200 In order to make your own changes locally and test them by hand, simply edit
201 modules in the local ``SCons`` subdirectory tree and then run
202 (see the section `Executing SCons Without Installing`_)::
204     $ python scripts/scons.py [arguments]
206 Or, if using the virtualenv/editable approach: ``scons [arguments]``
208 Note that the regular SCons development process makes heavy use of automated
209 testing.  See the `Testing`_ and `Typical Development Workflow`_ sections below for more
210 information about the automated regression tests and how they can be used in a
211 development cycle to validate that your changes don't break existing
212 functionality.
215 Debugging
216 =========
218 Python comes with a good interactive debugger.  When debugging changes by hand
219 (i.e., when not using the automated tests), you can invoke SCons under control
220 of the Python debugger by specifying the ``--debug=pdb`` option::
222     $ scons --debug=pdb [arguments]
223     > /home/knight/scons/SCons/Script/Main.py(927)_main()
224     -> default_warnings = [ SCons.Warnings.CorruptSConsignWarning,
225     (Pdb)
227 Once in the debugger, you can set breakpoints at lines in files in the build
228 engine modules by providing the path name of the file relative to the
229 top directory (that is, including the SCons/ as the first directory
230 component)::
232     (Pdb) b SCons/Tool/msvc.py:158
234 Since Python 3.7.0 you can also insert a call to the ``breakpoint()``
235 function in your code, call ``scons.py`` normally, and it will drop into
236 the debugger at that point.
238 The debugger supports single stepping, stepping into functions, printing
239 variables, etc.
241 When debugging unexpected behavior when running the test suite
242 (see the `Testing`_ section, below), it can get a bit more complicated.
243 For the Unit Tests, you will be running in-process, and so the
244 ``runtest.py`` script's debug option is helpful in getting things set up.
246 Trying to debug problems found by running the end-to-end tests is
247 more difficult, because the test automation harness re-invokes SCons and
248 captures output - essentially, an instance of SCons is being runs as
249 a "black box", and so it is considerably harder to interact with it
250 effectively. The way forward is usually to add statements to trace progress.
251 You can't just use the ``print`` function directly, or even ``sys.stdout.write()``
252 because those change the SCons output, and the end-to-end tests usually
253 look for matches of specific output strings to decide if a given SCons
254 invocation has behaved as expected - so interleaving your trace information
255 would cause lots of mismatches, and often obscure what you are trying to debug.
257 To deal with this, SCons supports a ``Trace()`` function that (by default) will
258 print messages to your console screen (``/dev/tty`` on UNIX or Linux, ``con`` on
259 Windows).  By adding ``Trace()`` calls to the SCons source code::
261     def sample_method(self, value):
262         from SCons.Debug import Trace
263         Trace('called sample_method(%s, %s)\n' % (self, value))
265 You can then run automated tests that print any arbitrary information you wish
266 about what's going on inside SCons, without interfering with the test
267 automation.
269 The ``Trace()`` function can also redirect its output to a file, rather than the
270 screen::
272     def sample_method(self, value):
273         from SCons.Debug import Trace
274         Trace('called sample_method(%s, %s)\n' % (self, value),
275               file='trace.out')
277 Where the ``Trace()`` function sends its output is stateful: once you use the
278 ``file=`` argument, all subsequent calls to ``Trace()`` send their output to the
279 same file, until another call with a ``file=`` argument is reached.
282 Testing
283 =======
285 Tests are run by the ``runtest.py`` script in the top directory.
287 There are two types of tests in this package:
289 1. Unit tests for individual SCons modules live underneath the SCons
290    subdirectory and have the same base name as the module with ``Tests.py``
291    appended--for example, the unit test for the ``Builder`` module in
292    ``Builder.py`` is the ``BuilderTests.py`` script.
294 2. End-to-end tests of SCons live in the ``test/`` subdirectory.
296 You may specifically list one or more tests to be run::
298         $ python runtest.py SCons/BuilderTests.py
300         $ python runtest.py test/option/option-j.py test/Program.py
302 You also use the ``-f`` option to execute just the tests listed in a specified
303 text file::
305         $ cat testlist.txt
306         test/option/option-j.py
307         test/Program.py
308         $ python runtest.py -f testlist.txt
310 One test must be listed per line, and any lines that begin with '#' will be
311 ignored (allowing you, for example, to comment out tests that are currently
312 passing and then uncomment all of the tests in the file for a final validation
313 run).
315 The runtest.py script also takes a ``-a`` option that searches the tree for all of
316 the tests and runs them::
318         $ python runtest.py -a
320 If a previous run had test failures, those are saved to logfile which
321 can be used to run just the failed tests - this is useful for the common
322 case of a change breaking a few things, and you want to first check that
323 a fix fixes those, before rerunning the full suite::
325         $ python runtest.py --retry
327 If more than one test is run, the ``runtest.py`` script prints a summary of
328 any tests that failed or yielded no result (usually these are skips due
329 to run-time checks of conditions). ``runtest.py`` has options to change
330 the output, just see the command's help message.
332 The above invocations all test directly the files underneath the ``SCons/``
333 subdirectory, and do not require that a build be performed first.
335 Typical Development Workflow
336 ============================
338 .. hint::
339     The point of this section is not to describe one dogmatic workflow.
340     Just running the test suite can be time-consuming, and getting a patch to
341     pass all of the tests can be more so.  If you're genuinely blocked, it may
342     make more sense to submit a patch with a note about which tests still
343     fail, and how.  Someone else may be able to take your "initial draft" and
344     figure out how to improve it to fix the rest of the tests.  So there's
345     plenty of room for use of good judgement.
347 The various techniques described in the above sections can be combined to
348 create simple and effective workflows that allow you to validate that patches
349 you submit to SCons don't break existing functionality and have adequate
350 testing, thereby increasing the speed with which they can be integrated.
352 For example, suppose your project's SCons configuration is blocked by an SCons
353 bug, and you decide you want to fix it and submit the patch.  Here's one
354 possible way to go about doing that (using UNIX/Linux as the development
355 platform, Windows users can translate as appropriate)):
357 - Change to the top of your checked-out SCons tree.
359 - Confirm that the bug still exists in this version of SCons by using the ``-C``
360   option to run the broken build::
362       $ python scripts/scons.py -C /home/me/broken_project .
364 - Fix the bug in SCons by editing appropriate module files underneath
365   SCons.
367 - Confirm that you've fixed the bug affecting your project::
369       $ python scripts/scons.py -C /home/me/broken_project .
371 - Test to see if your fix had any unintended side effects that break existing
372   functionality::
374       $ python runtest.py -a -o test.log
376   Be patient, there are more than 1100 test scripts in the whole suite
377   (using a ``-j`` option pretty much always helps. For example, if you have
378   an 8-core processor, try ``runtest.py -j 8```).
380   If any test scripts fail, they will be listed in a summary at the end of the
381   log file.  Some test scripts may also report NO RESULT because (for example)
382   your local system is the wrong type or doesn't have some installed utilities
383   necessary to run the script.  In general, you can ignore the NO RESULT list,
384   beyond having checked once that the tests that matter to your change are
385   actually being executed on your test system!  These failed tests are
386   automatically saved to ``failed_tests.log``.
388 - Now debug the test failures and fix them, either by changing SCons, or by
389   making necessary changes to the tests (if, for example, you have a strong
390   reason to change functionality, or if you find that the bug really is in the
391   test script itself).  After each change, use the ``--retry``
392   option to examine the effects of the change on the subset of tests that
393   last failed::
395       $ [edit]
396       $ python runtest.py --retry
398   Repeat this until all of the tests that originally failed now pass.
400 - Now you need to go back and validate that any changes you made while getting
401   the tests to pass didn't break the fix you originally put in, and didn't
402   introduce any *additional* unintended side effects that broke other tests::
404       $ python scripts/scons.py -C /home/me/broken_project .
405       $ python runtest.py -a -o test.log
407 Of course, the above is only one suggested workflow.  In practice, there is a
408 lot of room for judgment and experience to make things go quicker.  For
409 example, if you're making a change to just the Java support, you might start
410 looking for regressions by just running the ``test/Java/\*.py`` tests instead of
411 running all tests with ``runtest.py -a``.
413 - To actually submit the fix and any test work as a Pull Request,
414   there will be some version control steps. For example::
416       $ git checkout -b fix-1387
417       $ git modified     # check that this reports your expected list
418       $ git add `git modified`
419       $ git commit -s    # fill in a good description of your changes
421   And proceed to push the change as a PR.
424 Building Packages
425 =================
427 We use SCons (version 3.1.2 or newer) to build its own packages.  If you
428 already have an appropriate version of SCons installed on your system,
429 you can build everything by simply running it::
431     $ scons
433 If you don't have SCons already installed on your system,
434 you can run the build directly from the source tree
435 (see the section above about `Executing SCons Without Installing`_)::
437     $ python scripts/scons.py
439 Those are full builds: depending on the utilities installed on your system,
440 any or all of the following packages will be built::
442     SCons-4.4.0-py3-none-any.whl
443     SCons-4.4.0ayyyymmdd.tar.gz
444     SCons-4.4.0ayyyymmdd.zip
445     scons-doc-4.4.0ayyyymmdd.tar.gz
446     scons-local-4.4.0ayyyymmdd.tar.gz
447     scons-local-4.4.0ayyyymmdd.zip
449 The ``SConstruct`` file is supposed to be smart enough to avoid trying to build
450 packages for which you don't have the proper utilities installed.
452 If you receive a build error, please report it to the scons-devel mailing list
453 and open a bug report on the SCons bug tracker.
455 Note that in addition to creating the above packages, the default build will
456 also unpack one or more of the packages for testing.
458 If you're working on documentation and just want to make sure that still builds,
459 there's a "doc" target::
461     $ python scripts/scons.py doc
463 Contents of this Tree
464 =====================
466 Not guaranteed to be up-to-date (but better than nothing):
468 bench/
469     A subdirectory for benchmarking scripts, used to perform timing tests
470     to decide what specific idioms are most efficient for various parts of
471     the code base.  We check these in so they're available in case we have
472     to revisit any of these decisions in the future.
474 bin/
475     Miscellaneous utilities used in SCons development.  Right now,
476     some of the stuff here includes:
478     - a script that runs pychecker on our source tree;
480     - a script that counts source and test files and numbers of lines in each;
482     - a prototype script for capturing sample SCons output in xml files;
484     - a script that can profile and time a packaging build of SCons itself;
486     - a copy of xml_export, which can retrieve project data from SourceForge;
487       (obsolete, as project now lives on GitHub and PyPi).
489     - scripts and a Python module for translating the SCons home-brew XML
490       documentation tags into DocBook and man page format
492 bootstrap.py
493     Obsolete packaging logic - ignore this.
495 debian/
496     Files needed to construct a Debian package.
497     The contents of this directory are dictated by the
498     `Debian Policy Manual <https://www.debian.org/doc/debian-policy>`).
499     The package will not be accepted into the Debian distribution unless
500     the contents of this directory satisfy the relevant Debian policies.
501     At this point, this is a sample; SCons is packaged for Debian by the
502     Debian project itself (and thus inherited by projects which derive from it,
503     if they haven't made their own packages). See:
505     - `Debian scons packages <https://packages.debian.org/search?keywords=scons&searchon=names&suite=all&section=all>`_
506     - `Ubuntu scons packages <https://packages.ubuntu.com/search?keywords=scons&searchon=names&suite=all&section=all>`_
508 doc/
509     SCons documentation.  A variety of things here, in various stages of
510     (in)completeness. Note not all of the documentation is in ``doc`` -
511     for tools and other self-contained items, there is often a documentation
512     file together with the source, with a ``.xml`` suffix, in the same
513     way there is often a unit-test file kept together with the source it tests.
515 LICENSE
516     A copy of the copyright and terms under which SCons is distributed (the
517     Open Source Initiative-approved MIT license).
519 LICENSE-local
520     A copy of the copyright and terms under which SCons is distributed for
521     inclusion in the scons-local-{version} packages.  This is the same as
522     LICENSE with a preamble that specifies the licensing terms are for SCons
523     itself, not any other package that includes SCons.
525 README.rst
526     What you're looking at right now.
528 README-local.rst
529     A README file for inclusion in the scons-local-{version} packages.
530     Similar to this file, but stripped down and modified for people looking at
531     including SCons in their shipped software.
533 README-SF.rst
534     A README file the SourceForge project page - although the project is
535     no longer developed on SourceForge, this still serves as a download
536     location.
538 runtest.py
539     Script for running SCons tests.  By default, this will run a test against
540     the code in the local SCons tree, so you don't have to do a build before
541     testing your changes.
543 SConstruct
544     The file describing to SCons how to build the SCons distribution.
546     (It has been pointed out that it's hard to find the SCons API in this
547     SConstruct file, and that it looks a lot more like a pure Python script
548     than a build configuration file.  That's mainly because all of the magick
549     we have to perform to deal with all of the different packaging formats
550     requires a lot of pure Python manipulation.  In other words, don't look at
551     this file for an example of how easy it is to use SCons to build "normal"
552     software.)
554 SCons/
555     This is the source code of the engine, plus unit tests and
556     documentation stubs kept together with pieces of the engine.
558 test/
559     End-to-end tests of the SCons utility itself.
560     These are separate from the individual module unit tests.
562 testing/
563     SCons testing framework.