| ============== |
| MyFirstTypoFix |
| ============== |
| |
| .. contents:: |
| :local: |
| |
| Introduction |
| ============ |
| |
| This tutorial will guide you through the process of making a change to |
| LLVM, and contributing it back to the LLVM project. |
| |
| .. note:: |
| The code changes presented here are only an example and not something you |
| should actually submit to the LLVM project. For your first real change to LLVM, |
| the code will be different but the rest of the guide will still apply. |
| |
| We'll be making a change to Clang, but the steps for other parts of LLVM are the same. |
| Even though the change we'll be making is simple, we're going to cover |
| steps like building LLVM, running the tests, and code review. This is |
| good practice, and you'll be prepared for making larger changes. |
| |
| We'll assume you: |
| |
| - know how to use an editor, |
| |
| - have basic C++ knowledge, |
| |
| - know how to install software on your system, |
| |
| - are comfortable with the command line, |
| |
| - have basic knowledge of git. |
| |
| |
| The change we're making |
| ----------------------- |
| |
| Clang has a warning for infinite recursion: |
| |
| .. code:: console |
| |
| $ echo "void foo() { foo(); }" > ~/test.cc |
| $ clang -c -Wall ~/test.cc |
| test.cc:1:12: warning: all paths through this function will call itself [-Winfinite-recursion] |
| |
| This is clear enough, but not exactly catchy. Let's improve the wording |
| a little: |
| |
| .. code:: console |
| |
| test.cc:1:12: warning: to understand recursion, you must first understand recursion [-Winfinite-recursion] |
| |
| |
| Dependencies |
| ------------ |
| |
| We're going to need some tools: |
| |
| - git: to check out the LLVM source code, |
| |
| - a C++ compiler: to compile LLVM source code. You'll want `a recent |
| version <host_cpp_toolchain>` of Clang, GCC, or Visual Studio. |
| |
| - CMake: used to configure how LLVM should be built on your system, |
| |
| - ninja: runs the C++ compiler to (re)build specific parts of LLVM, |
| |
| - python: to run the LLVM tests. |
| |
| As an example, on Ubuntu: |
| |
| .. code:: console |
| |
| $ sudo apt-get install git clang cmake ninja-build python |
| |
| |
| Building LLVM |
| ============= |
| |
| |
| Checkout |
| -------- |
| |
| The source code is stored `on |
| Github <https://github.com/llvm/llvm-project>`__ in one large repository |
| ("the monorepo"). |
| |
| It may take a while to download! |
| |
| .. code:: console |
| |
| $ git clone https://github.com/llvm/llvm-project.git |
| |
| This will create a directory "llvm-project" with all of the source |
| code. (Checking out anonymously is OK - pushing commits uses a different |
| mechanism, as we'll see later.) |
| |
| Configure your workspace |
| ------------------------ |
| |
| Before we can build the code, we must configure exactly how to build it |
| by running CMake. CMake combines information from three sources: |
| |
| - explicit choices you make (is this a debug build?) |
| |
| - settings detected from your system (where are libraries installed?) |
| |
| - project structure (which files are part of 'clang'?) |
| |
| First, create a directory to build in. Usually, this is ``llvm-project/build``. |
| |
| .. code:: console |
| |
| $ mkdir llvm-project/build |
| $ cd llvm-project/build |
| |
| Now, run CMake: |
| |
| .. code:: console |
| |
| $ cmake -G Ninja ../llvm -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=clang |
| |
| If all goes well, you'll see a lot of "performing test" lines, and |
| finally: |
| |
| .. code:: console |
| |
| Configuring done |
| Generating done |
| Build files have been written to: /path/llvm-project/build |
| |
| And you should see a ``build.ninja`` file in the current directory. |
| |
| Let's break down that last command a little: |
| |
| - **-G Ninja**: Tells CMake that we're going to use ninja to build, and to create |
| the ``build.ninja`` file. |
| |
| - **../llvm**: this is the path to the source of the "main" LLVM |
| project |
| |
| - The two **-D** flags set CMake variables, which override |
| CMake/project defaults: |
| |
| - **CMAKE_BUILD_TYPE=Release**: build in optimized mode, which is |
| (surprisingly) the fastest option. |
| |
| If you want to run under a debugger, you should use the default Debug |
| (which is totally unoptimized, and will lead to >10x slower test |
| runs) or RelWithDebInfo which is a halfway point. |
| |
| Assertions are not enabled in ``Release`` builds by default. |
| You can enable them using ``LLVM_ENABLE_ASSERTIONS=ON``. |
| |
| - **LLVM_ENABLE_PROJECTS=clang**: this lists the LLVM subprojects |
| you are interested in building, in addition to LLVM itself. Multiple |
| projects can be listed, separated by semicolons, such as ``clang;lldb``. |
| In this example, we'll be making a change to Clang, so we only add clang. |
| |
| Finally, create a symlink (or copy) of ``llvm-project/build/compile-commands.json`` |
| into ``llvm-project/``: |
| |
| .. code:: console |
| |
| $ ln -s build/compile_commands.json ../ |
| |
| (This isn't strictly necessary for building and testing, but allows |
| tools like clang-tidy, clang-query, and clangd to work in your source |
| tree). |
| |
| |
| Build and test |
| -------------- |
| |
| Finally, we can build the code! It's important to do this first, to |
| ensure we're in a good state before making changes. But what to build? |
| In ninja, you specify a **target**. If we just want to build the clang |
| binary, our target name is "clang" and we run: |
| |
| .. code:: console |
| |
| $ ninja clang |
| |
| The first time we build will be very slow - Clang + LLVM is a lot of |
| code. But incremental builds are fast: ninja will only rebuild the parts |
| that have changed. When it finally finishes you should have a working |
| clang binary. Try running: |
| |
| .. code:: console |
| |
| $ bin/clang --version |
| |
| There's also a target for building and running all the clang tests: |
| |
| .. code:: console |
| |
| $ ninja check-clang |
| |
| This is a common pattern in LLVM: check-llvm is all the checks for the core of |
| LLVM, other projects have targets like ``check-lldb``, ``check-flang`` and so on. |
| |
| |
| Making changes |
| ============== |
| |
| |
| The Change |
| ---------- |
| |
| We need to find the file containing the error message. |
| |
| .. code:: console |
| |
| $ git grep "all paths through this function" .. |
| ../clang/include/clang/Basic/DiagnosticSemaKinds.td: "all paths through this function will call itself">, |
| |
| The string that appears in ``DiagnosticSemaKinds.td`` is the one that is |
| printed by Clang. ``*.td`` files define tables - in this case it's a list |
| of warnings and errors clang can emit and their messages. Let's update |
| the message in your favorite editor: |
| |
| .. code:: console |
| |
| $ vi ../clang/include/clang/Basic/DiagnosticSemaKinds.td |
| |
| Find the message (it should be under ``warn_infinite_recursive_function``). |
| Change the message to "in order to understand recursion, you must first understand recursion". |
| |
| |
| Test again |
| ---------- |
| |
| To verify our change, we can build clang and manually check that it |
| works. |
| |
| .. code:: console |
| |
| $ ninja clang |
| $ bin/clang -c -Wall ~/test.cc |
| test.cc:1:12: warning: in order to understand recursion, you must first understand recursion [-Winfinite-recursion] |
| |
| We should also run the tests to make sure we didn't break something. |
| |
| .. code:: console |
| |
| $ ninja check-clang |
| |
| Notice that it is much faster to build this time, but the tests take |
| just as long to run. Ninja doesn't know which tests might be affected, |
| so it runs them all. |
| |
| .. code:: console |
| |
| ******************** |
| Failing Tests (1): |
| Clang :: SemaCXX/warn-infinite-recursion.cpp |
| |
| Well, that makes sense… and the test output suggests it's looking for |
| the old string "call itself" and finding our new message instead. |
| Note that more tests may fail in a similar way as new tests are added |
| over time. |
| |
| Let's fix it by updating the expectation in the test. |
| |
| .. code:: console |
| |
| $ vi ../clang/test/SemaCXX/warn-infinite-recursion.cpp |
| |
| Everywhere we see ``// expected-warning{{call itself}}`` (or something similar |
| from the original warning text), let's replace it with |
| ``// expected-warning{{to understand recursion}}``. |
| |
| Now we could run **all** the tests again, but this is a slow way to |
| iterate on a change! Instead, let's find a way to re-run just the |
| specific test. There are two main types of tests in LLVM: |
| |
| - **lit tests** (e.g. ``SemaCXX/warn-infinite-recursion.cpp``). |
| |
| These are fancy shell scripts that run command-line tools and verify the |
| output. They live in files like |
| ``clang/**test**/FixIt/dereference-addressof.c``. Re-run like this: |
| |
| .. code:: console |
| |
| $ bin/llvm-lit -v ../clang/test/SemaCXX/warn-infinite-recursion.cpp |
| |
| - **unit tests** (e.g. ``ToolingTests/ReplacementTest.CanDeleteAllText``) |
| |
| These are C++ programs that call LLVM functions and verify the results. |
| They live in suites like ToolingTests. Re-run like this: |
| |
| .. code:: console |
| |
| $ ninja ToolingTests && tools/clang/unittests/Tooling/ToolingTests --gtest_filter=ReplacementTest.CanDeleteAllText |
| |
| |
| Commit locally |
| -------------- |
| |
| We'll save the change to a local git branch. This lets us work on other |
| things while the change is being reviewed. Changes should have a |
| title and description, to explain to reviewers and future readers of the code why |
| the change was made. |
| |
| For now, we'll only add a title. |
| |
| .. code:: console |
| |
| $ git checkout -b myfirstpatch |
| $ git commit -am "[clang][Diagnostic] Clarify -Winfinite-recursion message" |
| |
| Now we're ready to send this change out into the world! |
| |
| The ``[clang]`` and ``[Diagnostic]`` prefixes are what we call tags. This loose convention |
| tells readers of the git log what areas a change is modifying. If you don't know |
| the tags for the modules you've changed, you can look at the commit history |
| for those areas of the repository. |
| |
| .. code:: console |
| |
| $ git log --oneline ../clang/ |
| |
| Or using GitHub, for example https://github.com/llvm/llvm-project/commits/main/clang. |
| |
| Tagging is imprecise, so don't worry if you are not sure what to put. Reviewers |
| will suggest some if they think they are needed. |
| |
| Code review |
| =========== |
| |
| Uploading a change for review |
| ----------------------------- |
| |
| LLVM code reviews happen through pull-request on GitHub, see the |
| :ref:`GitHub <github-reviews>` documentation for how to open |
| a pull-request on GitHub. |
| |
| Finding a reviewer |
| ------------------ |
| |
| Changes can be reviewed by anyone in the LLVM community. For larger and more |
| complicated changes, it's important that the |
| reviewer has experience with the area of LLVM and knows the design goals |
| well. The author of a change will often assign a specific reviewer. ``git blame`` |
| and ``git log`` can be useful to find previous authors who can review. |
| |
| Our GitHub bot will also tag and notify various "teams" around LLVM. The |
| team members contribute and review code for those specific areas regularly, |
| so one of them will review your change if you don't pick anyone specific. |
| |
| Review process |
| -------------- |
| |
| When you open a pull-request, some automation will add a comment and |
| notify different members of the sub-projects depending on the parts you have |
| changed. |
| |
| Within a few days, someone should start the review. They may add |
| themselves as a reviewer, or simply start leaving comments. You'll get |
| another email any time the review is updated. For more detail see the |
| :ref:`Code Review Poilicy <code_review_policy>`. |
| |
| Comments |
| ~~~~~~~~ |
| |
| The reviewer can leave comments on the change, and you can reply. Some |
| comments are attached to specific lines, and appear interleaved with the |
| code. You can reply to these. Perhaps to clarify what was asked or to tell the |
| reviewer that you have done what was asked. |
| |
| Updating your change |
| ~~~~~~~~~~~~~~~~~~~~ |
| |
| If you make changes in response to a reviewer's comments, simply update |
| your branch with more commits and push to your GitHub fork of ``llvm-project``. |
| It is best if you answer comments from the reviewer directly instead of expecting |
| them to read through all the changes again. |
| |
| For example you might comment "I have done this." or "I was able to this part |
| but have a question about...". |
| |
| Review expectations |
| ------------------- |
| |
| In order to make LLVM a long-term sustainable effort, code needs to be |
| maintainable and well tested. Code reviews help to achieve that goal. |
| Especially for new contributors, that often means many rounds of reviews |
| and push-back on design decisions that do not fit well within the |
| overall architecture of the project. |
| |
| For your first patches, this means: |
| |
| - be kind, and expect reviewers to be kind in return - LLVM has a |
| :ref:`Code of Conduct <LLVM Community Code of Conduct>` |
| that everyone should be following; |
| |
| - be patient - understanding how a new feature fits into the |
| architecture of the project is often a time consuming effort, and |
| people have to juggle this with other responsibilities in their |
| lives; **ping the review once a week** when there is no response; |
| |
| - if you can't agree, generally the best way is to do what the reviewer |
| asks; we optimize for readability of the code, which the reviewer is |
| in a better position to judge; if this feels like it's not the right |
| option, you can ask them in a comment or add another reviewer to get a second |
| opinion. |
| |
| |
| Accepting a pull request |
| ------------------------ |
| |
| When the reviewer is happy with the change, they will **Approve** the |
| pull request. They may leave some more minor comments that you should |
| address before it is merged, but at this point the review is complete. |
| It's time to get it merged! |
| |
| |
| Commit access |
| ============= |
| |
| Commit by proxy |
| --------------- |
| |
| As this is your first change, you won't have access to merge it |
| yourself yet. The reviewer **does not know this**, so you need to tell |
| them! Leave a comment on the review like: |
| |
| Thanks @<username of reviewer>. I don't have commit access, can you merge this |
| PR for me? |
| |
| The pull-request will be closed and you will be notified by GitHub. |
| |
| Getting commit access |
| --------------------- |
| |
| Once you've contributed a handful of patches to LLVM, start to think |
| about getting commit access yourself. It's probably a good idea if: |
| |
| - you've landed 3-5 patches of larger scope than "fix a typo" |
| |
| - you'd be willing to review changes that are closely related to yours |
| |
| - you'd like to keep contributing to LLVM. |
| |
| |
| The process is described in the :ref:`developer policy document <obtaining_commit_access>`. |
| |
| With great power |
| ---------------- |
| |
| Actually, this would be a great time to read the rest of the :ref:`developer |
| policy <developer_policy>` too. |
| |
| |
| .. _MyFirstTypoFix Issues After Landing Your PR: |
| |
| Issues After Landing Your PR |
| ============================ |
| |
| Once your change is submitted it will be picked up by automated build |
| bots that will build and test your patch in a variety of configurations. |
| |
| The "console" view at http://lab.llvm.org/buildbot/#/console displays results |
| for specific commits. If you want to follow how your change is affecting the |
| build bots, this should be the first place to look. |
| |
| The columns are build configurations and the rows are individual commits. Along |
| the rows are colored bubbles. The color of the bubble represents the build's |
| status. Green is passing, red has failed and yellow is a build in progress. |
| |
| A red build may have already been failing before your change was committed. This |
| means you didn't break the build but you should check that you did not make it |
| any worse by adding new problems. |
| |
| .. note:: |
| Only recent changes are shown in the console view. If your change is not |
| there, rely on PR comments and build bot emails to notify you of any problems. |
| |
| If there is a problem in a build that includes your changes, you may receive |
| a report by email or as a comment on your PR. Please check whether the problem |
| has been caused by your changes specifically. As builds contain changes from |
| many authors and sometimes fail due to unrelated infrastructure problems. |
| |
| To see the details of a build, click the bubble in the console view, or the link |
| provided in the problem report. You will be able to view and download logs for |
| each stage of that build. |
| |
| If you need help understanding the problem, or have any other questions, you can |
| ask them as a comment on your PR, or on `Discord <https://discord.com/invite/xS7Z362>`__. |
| |
| If you do not receive any reports of problems, no action is required from you. |
| Your changes are working as expected, well done! |
| |
| Reverts |
| ------- |
| |
| If your change has caused a problem, it should be reverted as soon as possible. |
| This is a normal part of :ref:`LLVM development <revert_policy>`, |
| that every committer (no matter how experienced) goes through. |
| |
| If you are in any doubt whether your change can be fixed quickly, revert it. |
| Then you have plenty of time to investigate and produce a solid fix. |
| |
| Someone else may revert your change for you, or you can create a revert pull request using |
| the `GitHub interface <https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/reverting-a-pull-request>`__. |
| Add your original reviewers to this new pull request if possible. |
| |
| Conclusion |
| ========== |
| |
| Now you should have an understanding of the life cycle of a contribution to the |
| LLVM Project. |
| |
| If some details are still unclear, do not worry. The LLVM Project's process does |
| differ from what you may be used to elsewhere on GitHub. Within the project |
| the expectations of different sub-projects may vary too. |
| |
| So whatever you are contributing to, know that we are not expecting perfection. |
| Please ask questions whenever you are unsure, and expect that if you have missed |
| something, someone will politely point it out and help you address it. |