Go: Difference between revisions

A-H (talk | contribs)
Provide more examples, explain use cases with titles.
DHCP (talk | contribs)
m use monospace formatting where applicable, add more links, update link to the Go homepage
 
(5 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[https://golang.org/ Go] is a statically-typed language with syntax loosely derived from that of C, adding garbage collected memory management, type safety, some dynamic-typing capabilities, additional built-in types such as variable-length arrays and key-value maps, and a large standard library.
[https://go.dev/ Go] is a statically-typed language with syntax loosely derived from that of C, adding garbage collected memory management, type safety, some dynamic-typing capabilities, additional built-in types such as variable-length arrays and key-value maps, and a large standard library.


== buildGoModule ==
== buildGoModule ==
nixpkgs includes a library function called '''buildGoModule''' ([https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/go/module.nix implementation]) See [https://nixos.org/manual/nixpkgs/stable/#sec-language-go nixpkgs manual '''Language: Go''']
nixpkgs includes a library function called '''buildGoModule''' ([https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/go/module.nix implementation]) See [https://nixos.org/manual/nixpkgs/stable/#sec-language-go nixpkgs manual '''Language: Go''']


`buildGoModule` uses the version of Go that's included in `nixpkgs` to build the software.
<code>buildGoModule</code> uses the version of Go that's included in <code>nixpkgs</code> to build the software.


==== Using a specific version of Go ====
==== Using a specific version of Go ====
To build for a specific version of Go, you may need to find the appropriate `pkgs.buildGoXXXModule` function to use.
To build for a specific version of Go, you may need to find the appropriate <code>pkgs.buildGoXXXModule</code> function to use.


This function may not be present in the version of nixpkgs that you're using, for example, `buildGo122Module` is not available in `github:NixOS/nixpkgs/nixos-23.05`, but is available in `github:NixOS/nixpkgs/nixos-unstable`.
This function may not be present in the version of nixpkgs that you're using, for example, <code>buildGo122Module</code> is not available in <code>github:NixOS/nixpkgs/nixos-23.05</code>, but is available in <code>github:NixOS/nixpkgs/nixos-unstable</code>.


==== Subpackages ====
==== Subpackages ====
By default, `buildGoModule` will attempt to build the `main` package that's in the root of the source code location.
By default, <code>buildGoModule</code> will attempt to build the <code>main</code> package that's in the root of the source code location.


However, it's a common pattern in Go applications to have binaries within the `./cmd/binary-name` directory instead.
However, it's a common pattern in Go applications to have binaries within the <code>./cmd/binary-name</code> directory instead.


Setting the `subPackages` attribute to be a list of the packages to build supports this pattern.
Setting the <code>subPackages</code> attribute to be a list of the packages to build supports this pattern.


==== Example (downloading source code from Github) ====
==== Example (downloading source code from Github) ====
The following `flake.nix` demonstrates how to build a Go module, where the source code is located in Github. To use it, copy this file as `flake.nix` into an empty directory on your computer, and run `nix build`. Nix will download the source code, including dependencies, and produce a `./result` folder containing a `ziti` binary.
The following <code>flake.nix</code> demonstrates how to build a Go module, where the source code is located in Github. To use it, copy this file as <code>flake.nix</code> into an empty directory on your computer, and run <code>nix build</code>. Nix will download the source code, including dependencies, and produce a <code>./result</code> folder containing a <code>ziti</code> binary.


Running `nix shell` will create a shell, where you can execute the `ziti` binary.<syntaxhighlight lang="nix">
Running <code>nix shell</code> will create a shell, where you can execute the <code>ziti</code> binary.<syntaxhighlight lang="nix">
{
{
   description = "OpenZiti";
   description = "OpenZiti";
Line 43: Line 43:
     {
     {
       packages = forAllSystems ({ pkgs }: {
       packages = forAllSystems ({ pkgs }: {
         default = pkgs.buildGo122Module {
         default = pkgs.buildGo122Module rec {
           name = "openziti";
           pname = "openziti";
          version = "1.0.0";
           subPackages = [ "ziti" ];
           subPackages = [ "ziti" ];
           src = pkgs.fetchFromGitHub {
           src = pkgs.fetchFromGitHub {
             owner = "openziti";
             owner = "openziti";
             repo = "ziti";
             repo = "ziti";
             rev = "v1.0.0";
             rev = "v${version}";
             sha256 = "sha256-2li/+XWKk+lybB1DE0unKvQrA0pKE9VIRFoEYMcbLS8=";
             sha256 = "sha256-2li/+XWKk+lybB1DE0unKvQrA0pKE9VIRFoEYMcbLS8=";
           };
           };
Line 61: Line 62:


==== Example (local source) ====
==== Example (local source) ====
If you want to build a local project with Nix, replace the `src` attribute to be the local directory, e.g.:<syntaxhighlight lang="nix">
If you want to build a local project with Nix, replace the <code>src</code> attribute to be the local directory, e.g.:<syntaxhighlight lang="nix">
   some-package = buildGoModule {
   some-package = buildGoModule {
     src = ./.
     src = ./.
Line 91: Line 92:


== Using cgo on NixOS ==
== Using cgo on NixOS ==
On NixOS, include files and libraries aren't kept in a system-wide search path. If a Go program uses cgo and attempts to include C header files, or link against libraries, compilation is likely to fail.
On NixOS, include files and libraries aren't kept in a system-wide search path. If a Go program uses [https://go.dev/wiki/cgo cgo] and attempts to include [[C]] header files, or link against libraries, compilation is likely to fail.


In order to expose header files and libraries in environment variable search paths, <tt>nix-shell</tt> can be used to enter an environment which provides the requested development dependencies.
In order to expose header files and libraries in environment variable search paths, <tt>nix-shell</tt> can be used to enter an environment which provides the requested development dependencies.


For example, suppose a Go program includes <tt>&lt;sys/capability.h&gt;</tt> (provided by <tt>libcap</tt>), and links against <tt>libcap</tt>. To obtain an environment in which the program can be compiled, run:
For example, suppose a Go program includes <code><tt>&lt;sys/capability.h&gt;</tt></code> (provided by <tt>libcap</tt>), and links against <tt>libcap</tt>. To obtain an environment in which the program can be compiled, run:


<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
Line 108: Line 109:
If you intend to compile against glibc statically (such as via <tt>go build -ldflags "-s -w -linkmode external -extldflags -static"</tt>), add <tt>glibc.static</tt> to the list of packages passed to <tt>nix-shell</tt>.
If you intend to compile against glibc statically (such as via <tt>go build -ldflags "-s -w -linkmode external -extldflags -static"</tt>), add <tt>glibc.static</tt> to the list of packages passed to <tt>nix-shell</tt>.


If you encounter [https://github.com/go-delve/delve/issues/3085 this issue] and receive an error about _FORTIFY_SOURCE when running delve (for example in VSCode), put <tt>hardeningDisable = [ "fortify" ];</tt> inside shell.nix or in the <tt>mkShell</tt> invocation argument like this:
If you encounter [https://github.com/go-delve/delve/issues/3085 this issue] and receive an error about <code>_FORTIFY_SOURCE</code> when running delve (for example in [[Visual Studio Code|VSCode]]), put <tt>hardeningDisable = [ "fortify" ];</tt> inside <code>shell.nix</code> or in the <tt>mkShell</tt> invocation argument like this:
<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
pkgs.mkShell {
pkgs.mkShell {
Line 117: Line 118:


== Compile go program with static compile flag ==
== Compile go program with static compile flag ==
If <code>go build -ldflags "-s -w -linkmode external -extldflags -static"</code> fails on NixOS, with the error message <code>cannot find `-lpthread</code> and <code>cannot find -lc</code> - it is because the linker cannot find static glibc to link with. You need to have glibc.static in your environment (and have CFLAGS/LDFLAGS adjusted accordingly).
If <code>go build -ldflags "-s -w -linkmode external -extldflags -static"</code> fails on NixOS, with the error message <code>cannot find `-lpthread</code> and <code>cannot find -lc</code> - it is because the linker cannot find static glibc to link with. You need to have <tt>glibc.static</tt> in your environment (and have <code>CFLAGS</code>/<code>LDFLAGS</code> adjusted accordingly).
One way to achieve this is to have something like the following as <code>shell.nix</code> and run the compilation in a nix-shell:
One way to achieve this is to have something like the following as <code>shell.nix</code> and run the compilation in a <tt>nix-shell</tt>:


<syntaxHighlight lang=nix>
<syntaxHighlight lang=nix>
Line 133: Line 134:
== Compile go program with static compile flag (take 2) ==
== Compile go program with static compile flag (take 2) ==


Linking against glibc.static does not really work because glibc does not really like static linking. You get a warning like <code>warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking</code>. To really create a static build, use musl. Example based on buildGoModule example from documentation:
Linking against <tt>glibc.static</tt> does not really work because glibc does not really like static linking. You get a warning like <code>warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking</code>. To really create a static build, use musl. Example based on <code>buildGoModule</code> example from documentation:


<syntaxHighlight lang=nix>
<syntaxHighlight lang=nix>
Line 172: Line 173:


[[Category:Languages]]
[[Category:Languages]]
[[Category:Applications]]
[[Category:Go]]