| ============== |
| 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. 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 |
| input.cc:1:14: 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 |
| |
| input.cc:1:14: 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 <https://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library>`__ |
| 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, |
| |
| - arcanist: for uploading changes for review, |
| |
| As an example, on Ubuntu: |
| |
| .. code:: console |
| |
| $ sudo apt-get install git clang cmake ninja-build python arcanist |
| |
| |
| 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. |
| |
| Let's break down that last command a little: |
| |
| - **-G Ninja**: we're going to use ninja to build; please create |
| build.ninja |
| |
| - **../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. |
| **CMAKE\ BUILD\ TYPE** affects code generation only, assertions are |
| on by default regardless! **LLVM\ ENABLE\ ASSERTIONS=Off** disables |
| them. |
| |
| - **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 |
| should build it. |
| |
| Finally, create a symlink (or a 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 core, |
| other projects have targets like check-lldb. |
| |
| |
| Making changes |
| ============== |
| |
| |
| Edit |
| ---- |
| |
| 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 -Wall ~/test.cc |
| |
| **/path/test.cc:1:124:** **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 |
| |
| ******************** |
| Testing Time: 408.84s |
| ******************** |
| 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 time to 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 |
| description, to explain to reviewers and future readers of the code why |
| the change was made. |
| |
| .. code:: console |
| |
| $ git checkout -b myfirstpatch |
| $ git commit -am "[Diagnostic] Clarify -Winfinite-recursion message" |
| |
| Now we're ready to send this change out into the world! By the way, |
| There is a unwritten convention of using tag for your commit. Tags |
| usually represent modules that you intend to modify. If you don't know |
| the tags for your modules, you can look at the commit history : |
| https://github.com/llvm/llvm-project/commits/main. |
| |
| |
| Code review |
| =========== |
| |
| |
| Finding a reviewer |
| ------------------ |
| |
| Changes can be reviewed by anyone in the LLVM community who has commit |
| access.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 one). |
| |
| As our change is fairly simple, we'll add the cfe-commits mailing list |
| as a subscriber; anyone who works on clang can likely pick up the |
| review. (For changes outside clang, llvm-commits is the usual list. See |
| `http://lists.llvm.org/ <http://lists.llvm.org/mailman/listinfo>`__ for |
| all the \*-commits mailing lists). |
| |
| |
| Uploading a change for review |
| ----------------------------- |
| |
| LLVM code reviews happen at https://reviews.llvm.org. The web interface |
| is called Phabricator, and the code review part is Differential. You |
| should create a user account there for reviews (click "Log In" and then |
| "Register new account"). |
| |
| Now you can upload your change for review: |
| |
| .. code:: console |
| |
| $ arc diff HEAD^ |
| |
| This creates a review for your change, comparing your current commit |
| with the previous commit. You will be prompted to fill in the review |
| details. Your commit message is already there, so just add cfe-commits |
| under the "subscribers" section. It should print a code review URL: |
| https://reviews.llvm.org/D58291 You can always find your active reviews |
| on Phabricator under "My activity". |
| |
| |
| Review process |
| -------------- |
| |
| When you upload a change for review, an email is sent to you, the |
| cfe-commits list, and anyone else subscribed to these kinds of changes. |
| 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. The details are in the |
| `https://llvm.org/docs/CodeReview/ <https://llvm.org/docs/CodeReview.html>`__. |
| |
| |
| 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 either reply to these, or address them and mark them as |
| "done". Note that in-line replies are **not** sent straight away! They |
| become "draft" comments and you must click "Submit" at the bottom of the |
| page. |
| |
| |
| Updating your change |
| ~~~~~~~~~~~~~~~~~~~~ |
| |
| If you make changes in response to a reviewer's comments, simply run |
| |
| .. code:: console |
| |
| $ arc diff |
| |
| again to update the change and notify the reviewer. Typically this is a |
| good time to send any draft comments as well. |
| |
| |
| Accepting a revision |
| ~~~~~~~~~~~~~~~~~~~~ |
| |
| When the reviewer is happy with the change, they will **Accept** the |
| revision. They may leave some more minor comments that you should |
| address, but at this point the review is complete. It's time to get it |
| committed! |
| |
| |
| Commit by proxy |
| --------------- |
| |
| As this is your first change, you won't have access to commit it |
| yourself yet. The reviewer **doesn't know this**, so you need to tell |
| them! Leave a message on the review like: |
| |
| Thanks @somellvmdev. I don't have commit access, can you land this |
| patch for me? Please use "My Name my@email" to commit the change. |
| |
| The review will be updated when the change is committed. |
| |
| |
| 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 `Code |
| of Conduct <https://llvm.org/docs/CodeOfConduct.html>`__; |
| |
| - 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 contact the cfe-dev mailing list to get more feedback |
| on the direction; |
| |
| |
| 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. |
| |
| |
| Getting commit access |
| --------------------- |
| |
| LLVM uses Git for committing changes. The details are in the `developer |
| policy |
| document <https://llvm.org/docs/DeveloperPolicy.html#obtaining-commit-access>`__. |
| |
| |
| With great power |
| ---------------- |
| |
| Actually, this would be a great time to read the rest of the `developer |
| policy <https://llvm.org/docs/DeveloperPolicy.html>`__, too. At minimum, |
| you need to be subscribed to the relevant commits list before landing |
| changes (e.g. llvm-commits@lists.llvm.org), as discussion often happens |
| there if a new patch causes problems. |
| |
| |
| Commit |
| ------ |
| |
| Let's say you have a change on a local git branch, reviewed and ready to |
| commit. Things to do first: |
| |
| - if you used multiple fine-grained commits locally, squash them into a |
| single commit. LLVM prefers commits to match the code that was |
| reviewed. (If you created one commit and then used "arc diff", you're |
| fine) |
| |
| - rebase your patch against the latest LLVM code. LLVM uses a linear |
| history, so everything should be based on an up-to-date origin/main. |
| |
| .. code:: console |
| |
| $ git pull --rebase https://github.com/llvm/llvm-project.git main |
| |
| - ensure the patch looks correct. |
| |
| .. code:: console |
| |
| $ git show |
| |
| - run the tests one last time, for good luck |
| |
| At this point git show should show a single commit on top of |
| origin/main. |
| |
| Now you can push your commit with |
| |
| .. code:: console |
| |
| $ git push https://github.com/llvm/llvm-project.git HEAD:main |
| |
| You should see your change `on |
| GitHub <https://github.com/llvm/llvm-project/commits/main>`__ within |
| minutes. |
| |
| |
| Post-commit errors |
| ------------------ |
| |
| 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. |
| |
| You can see all configurations and their current state in a waterfall |
| view at http://lab.llvm.org/buildbot/#/waterfall. The waterfall view is good |
| to get a general overview over the tested configurations and to see |
| which configuration have been broken for a while. |
| |
| The console view at http://lab.llvm.org/buildbot/#/console helps to get a |
| better understanding of the build results of a specific patch. If you |
| want to follow along how your change is affecting the build bots, **this |
| should be the first place to look at** - the colored bubbles correspond |
| to projects in the waterfall. |
| |
| If you see a broken build, do not despair - some build bots are |
| continuously broken; if your change broke the build, you will see a red |
| bubble in the console view, while an already broken build will show an |
| orange bubble. Of course, even when the build was already broken, a new |
| change might introduce a hidden new failure. |
| |
| | When you want to see more details how a specific build is broken, |
| click the red bubble. |
| | If post-commit error logs confuse you, do not worry too much - |
| everybody on the project is aware that this is a bit unwieldy, so |
| expect people to jump in and help you understand what's going on! |
| |
| buildbots, overview of bots, getting error logs. |
| |
| |
| Reverts |
| ------- |
| |
| if in doubt, revert and re-land. |
| |
| |
| Conclusion |
| ========== |
| |
| llvm is a land of contrasts. |