| <!--{ |
| "Title": "Tutorial: Getting started with multi-module workspaces" |
| }--> |
| |
| This tutorial introduces the basics of multi-module workspaces in Go. |
| With multi-module workspaces, you can tell the Go command that you're |
| writing code in multiple modules at the same time and easily build and |
| run code in those modules. |
| |
| In this tutorial, you'll create two modules in a shared multi-module |
| workspace, make changes across those modules, and see the results |
| of those changes in a build. |
| |
| <!-- TODO TOC --> |
| |
| **Note:** For other tutorials, see [Tutorials](/doc/tutorial/index.html). |
| |
| ## Prerequisites |
| |
| * **An installation of Go 1.18 or later.** |
| * **A tool to edit your code.** Any text editor you have will work fine. |
| * **A command terminal.** Go works well using any terminal on Linux and Mac, |
| and on PowerShell or cmd in Windows. |
| |
| This tutorial requires go1.18 or later. Make sure you've installed Go at Go 1.18 or later using the |
| links at [go.dev/dl](https://go.dev/dl). |
| |
| ## Create a module for your code {#create_folder} |
| |
| To begin, create a module for the code you’ll write. |
| |
| 1. Open a command prompt and change to your home directory. |
| |
| On Linux or Mac: |
| |
| ``` |
| $ cd |
| ``` |
| |
| On Windows: |
| |
| ``` |
| C:\> cd %HOMEPATH% |
| ``` |
| |
| The rest of the tutorial will show a $ as the prompt. The commands you use |
| will work on Windows too. |
| |
| 2. From the command prompt, create a directory for your code called workspace. |
| |
| ``` |
| $ mkdir workspace |
| $ cd workspace |
| ``` |
| |
| 3. Initialize the module |
| |
| Our example will create a new module `hello` that will depend on the golang.org/x/example module. |
| |
| Create the hello module: |
| |
| ``` |
| $ mkdir hello |
| $ cd hello |
| $ go mod init example.com/hello |
| go: creating new go.mod: module example.com/hello |
| ``` |
| |
| Add a dependency on the golang.org/x/example module by using `go get`. |
| |
| ``` |
| $ go get golang.org/x/example |
| ``` |
| |
| Create hello.go in the hello directory with the following contents: |
| |
| ``` |
| package main |
| |
| import ( |
| "fmt" |
| |
| "golang.org/x/example/stringutil" |
| ) |
| |
| func main() { |
| fmt.Println(stringutil.Reverse("Hello")) |
| } |
| ``` |
| |
| Now, run the hello program: |
| |
| ``` |
| $ go run example.com/hello |
| olleH |
| ``` |
| |
| ## Create the workspace |
| |
| In this step, we'll create a `go.work` file to specify a workspace with the module. |
| |
| #### Initialize the workspace |
| |
| In the `workspace` directory, run: |
| |
| ``` |
| $ go work init ./hello |
| ``` |
| |
| The `go work init` command tells `go` to create a `go.work` file |
| for a workspace containing the modules in the `./hello` |
| directory. |
| |
| The `go` command produces a `go.work` file that looks like this: |
| |
| ``` |
| go 1.18 |
| |
| use ./hello |
| ``` |
| |
| The `go.work` file has similar syntax to `go.mod`. |
| |
| The `go` directive tells Go which version of Go the file should be |
| interpreted with. It's similar to the `go` directive in the `go.mod` |
| file. |
| |
| The `use` directive tells Go that the module in the `hello` |
| directory should be main modules when doing a build. |
| |
| So in any subdirectory of `workspace` the module will be active. |
| |
| #### Run the program in the workspace directory |
| |
| In the `workspace` directory, run: |
| |
| ``` |
| $ go run example.com/hello |
| olleH |
| ``` |
| |
| The Go command includes all the modules in the workspace as main modules. This allows us |
| to refer to a package in the module, even outside the module. Running the `go run` command |
| outside the module or the workspace would result in an error because the `go` command |
| wouldn't know which modules to use. |
| |
| Next, we'll add a local copy of the `golang.org/x/example` module to the workspace. We'll then |
| add a new function to the `stringutil` package that we can use instead of `Reverse`. |
| |
| ## Download and modify the `golang.org/x/example` module |
| |
| In this step, we'll download a copy of the Git repo containing the `golang.org/x/example` module, |
| add it to the workspace, and then add a new function to it that we will use from the hello program. |
| |
| 1. Clone the repository |
| |
| From the workspace directory, run the `git` command to clone the repository: |
| |
| ``` |
| $ git clone https://go.googlesource.com/example |
| Cloning into 'example'... |
| remote: Total 165 (delta 27), reused 165 (delta 27) |
| Receiving objects: 100% (165/165), 434.18 KiB | 1022.00 KiB/s, done. |
| Resolving deltas: 100% (27/27), done. |
| ``` |
| |
| 2. Add the module to the workspace |
| |
| ``` |
| $ go work use ./example |
| ``` |
| |
| The `go work use` command adds a new module to the go.work file. It will now look like this: |
| |
| ``` |
| go 1.18 |
| |
| use ( |
| ./hello |
| ./example |
| ) |
| ``` |
| |
| The module now includes both the `example.com/hello` module and the `golang.org/x/example` module. |
| |
| This will allow us to use the new code we will write in our copy of the `stringutil` module |
| instead of the version of the module in the module cache that we downloaded with the `go get` command. |
| |
| 3. Add the new function. |
| |
| We'll add a new function to uppercase a string to the `golang.org/x/example/stringutil` package. |
| |
| Create a new file named `toupper.go` in the `workspace/example/stringutil` directory containing the following contents: |
| |
| ``` |
| package stringutil |
| |
| import "unicode" |
| |
| // ToUpper uppercases all the runes in its argument string. |
| func ToUpper(s string) string { |
| r := []rune(s) |
| for i := range r { |
| r[i] = unicode.ToUpper(r[i]) |
| } |
| return string(r) |
| } |
| ``` |
| |
| 4. Modify the hello program to use the function. |
| |
| Modify the contents of `workspace/hello/hello.go` to contain the following contents: |
| |
| ``` |
| package main |
| |
| import ( |
| "fmt" |
| |
| "golang.org/x/example/stringutil" |
| ) |
| |
| func main() { |
| fmt.Println(stringutil.ToUpper("Hello")) |
| } |
| ``` |
| |
| #### Run the code in the workspace |
| |
| From the workspace directory, run |
| |
| ``` |
| $ go run example.com/hello |
| HELLO |
| ``` |
| |
| The Go command finds the `example.com/hello` module specified in the |
| command line in the `hello` directory specified by the `go.work` |
| file, and similarly resolves the `golang.org/x/example` import using |
| the `go.work` file. |
| |
| `go.work` can be used instead of adding [`replace`](https://go.dev/ref/mod#go-mod-file-replace) |
| directives to work across multiple modules. |
| |
| Since the two modules are in the same workspace it's easy |
| to make a change in one module and use it in another. |
| |
| #### Future step |
| |
| Now, to properly release these modules we'd need to make a release of the `golang.org/x/example` |
| module, for example at `v0.1.0`. This is usually done by tagging a commit on the module's version |
| control repository. See the |
| [module release workflow documentation](https://go.dev/doc/modules/release-workflow) |
| for more details. Once the release is done, we can increase the requirement on the |
| `golang.org/x/example` module in `hello/go.mod`: |
| |
| ``` |
| cd hello |
| go get golang.org/x/example@v0.1.0 |
| ``` |
| |
| That way, the `go` command can properly resolve the modules outside the workspace. |
| |
| ## Learn more about workspaces |
| |
| The `go` command has a couple of subcommands for working with workspaces in addition to `go work init` which |
| we saw earlier in the tutorial: |
| |
| - `go work use [-r] [dir]` adds a `use` directive to the `go.work` file for `dir`, |
| if it exists, and removes the `use` directory if the argument directory doesn't exist. The `-r` |
| flag examines subdirectories of `dir` recursively. |
| - `go work edit` edits the `go.work` file similarly to `go mod edit` |
| - `go work sync` syncs dependencies from the workspace's build list into each of the workspace modules. |
| |
| See [Workspaces](https://go.dev/ref/mod#workspaces) in the Go Modules Reference for more detail on |
| workspaces and `go.work` files. |