func buildBinaries()

in tools/build_gcsfuse/main.go [53:190]


func buildBinaries(dstDir, srcDir, version string, buildArgs []string) (err error) {
	osys := runtime.GOOS
	// Create the target structure.
	{
		dirs := []string{
			"bin",
			"sbin",
		}

		for _, d := range dirs {
			err = os.Mkdir(path.Join(dstDir, d), 0755)
			if err != nil {
				err = fmt.Errorf("mkdir: %w", err)
				return
			}
		}
	}

	pathEnv, exists := os.LookupEnv("PATH")
	if !exists {
		err = fmt.Errorf("$PATH not found in OS")
		return
	}

	// Create a directory to become GOPATH for our build below.
	gopath, err := os.MkdirTemp("", "build_gcsfuse_gopath")
	if err != nil {
		err = fmt.Errorf("TempDir: %w", err)
		return
	}
	defer os.RemoveAll(gopath)

	// Create a directory to become GOCACHE for our build below.
	var gocache string
	gocache, err = os.MkdirTemp("", "build_gcsfuse_gocache")
	if err != nil {
		err = fmt.Errorf("TempDir: %w", err)
		return
	}
	defer os.RemoveAll(gocache)

	// Make it appear as if the source directory is at the appropriate position
	// in $GOPATH.
	gcsfuseDir := path.Join(gopath, "src/github.com/googlecloudplatform/gcsfuse")
	err = os.MkdirAll(path.Dir(gcsfuseDir), 0700)
	if err != nil {
		err = fmt.Errorf("MkdirAll: %w", err)
		return
	}

	err = os.Symlink(srcDir, gcsfuseDir)
	if err != nil {
		err = fmt.Errorf("symlink: %w", err)
		return
	}

	// mount(8) expects a different name format on Linux.
	mountHelperName := "mount_gcsfuse"
	if osys == "linux" {
		mountHelperName = "mount.gcsfuse"
	}

	// Build the binaries.
	binaries := []struct {
		goTarget   string
		outputPath string
	}{
		{
			"github.com/googlecloudplatform/gcsfuse/v2",
			"bin/gcsfuse",
		},
		{
			"github.com/googlecloudplatform/gcsfuse/v2/tools/mount_gcsfuse",
			path.Join("sbin", mountHelperName),
		},
	}

	for _, bin := range binaries {
		log.Printf("Building %s to %s", bin.goTarget, bin.outputPath)

		// Set up arguments.
		cmd := exec.Command(
			"go",
			"build",
			"-C",
			srcDir,
			"-o",
			path.Join(dstDir, bin.outputPath))

		if path.Base(bin.outputPath) == "gcsfuse" {
			cmd.Args = append(
				cmd.Args,
				"-ldflags",
				fmt.Sprintf("-X github.com/googlecloudplatform/gcsfuse/v2/common.gcsfuseVersion=%s", version),
			)
			cmd.Args = append(cmd.Args, buildArgs...)
		}

		cmd.Args = append(cmd.Args, bin.goTarget)

		// Set up environment.
		cmd.Env = append(
			os.Environ(),
			"GO15VENDOREXPERIMENT=1",
			"GO111MODULE=auto",
			fmt.Sprintf("PATH=%s", pathEnv),
			fmt.Sprintf("GOROOT=%s", runtime.GOROOT()),
			fmt.Sprintf("GOPATH=%s", gopath),
			fmt.Sprintf("GOCACHE=%s", gocache),
			"CGO_ENABLED=0",
		)

		// Build.
		var output []byte
		output, err = cmd.CombinedOutput()
		if err != nil {
			err = fmt.Errorf("%v: %w\nOutput:\n%s", cmd, err, output)
			if strings.Contains(string(output), "flag provided but not defined: -C") {
				err = fmt.Errorf("%v: %w\nOutput:\n%s\nPlease upgrade to go version 1.20 or higher", cmd, err, output)
			}
			return
		}
	}

	// On Linux, also support `mount -t fuse.gcsfuse`. If there's no explicit
	// helper for this type, /sbin/mount.fuse will call the gcsfuse executable
	// directly, but it doesn't support the right argument format. So we install
	// an explicit helper.
	if osys == "linux" {
		err = os.Symlink("mount.gcsfuse", path.Join(dstDir, "sbin/mount.fuse.gcsfuse"))
		if err != nil {
			err = fmt.Errorf("symlink: %w", err)
			return
		}
	}

	return
}