Source file src/cmd/cgo/internal/testfortran/fortran_test.go

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package fortran
     6  
     7  import (
     8  	"internal/testenv"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"runtime"
    13  	"strings"
    14  	"testing"
    15  )
    16  
    17  func TestFortran(t *testing.T) {
    18  	testenv.MustHaveGoRun(t)
    19  	testenv.MustHaveCGO(t)
    20  
    21  	// Find the FORTRAN compiler.
    22  	fc := os.Getenv("FC")
    23  	if fc == "" {
    24  		fc, _ = exec.LookPath("gfortran")
    25  	}
    26  	if fc == "" {
    27  		t.Skip("fortran compiler not found (try setting $FC)")
    28  	}
    29  
    30  	var fcExtra []string
    31  	if strings.Contains(fc, "gfortran") {
    32  		// TODO: This duplicates but also diverges from logic from cmd/go
    33  		// itself. For example, cmd/go merely adds -lgfortran without the extra
    34  		// library path work. If this is what's necessary to run gfortran, we
    35  		// should reconcile the logic here and in cmd/go.. Maybe this should
    36  		// become a cmd/go script test to share that logic.
    37  
    38  		// Add -m32 if we're targeting 386, in case this is a cross-compile.
    39  		if runtime.GOARCH == "386" {
    40  			fcExtra = append(fcExtra, "-m32")
    41  		}
    42  
    43  		// Find libgfortran. If the FORTRAN compiler isn't bundled
    44  		// with the C linker, this may be in a path the C linker can't
    45  		// find on its own. (See #14544)
    46  		libExt := "so"
    47  		switch runtime.GOOS {
    48  		case "darwin":
    49  			libExt = "dylib"
    50  		case "aix", "openbsd", "windows":
    51  			libExt = "a"
    52  		}
    53  		libName := "libgfortran." + libExt
    54  		b, err := exec.Command(fc, append([]string{"-print-file-name=" + libName}, fcExtra...)...).CombinedOutput()
    55  		if err != nil {
    56  			t.Fatalf("error invoking %s: %s", fc, err)
    57  		}
    58  		libPath := strings.TrimSpace(string(b))
    59  		if libPath == libName {
    60  			t.Fatalf("Failed to get full library path for %q", libName)
    61  		}
    62  		libDir := filepath.Dir(libPath)
    63  		cgoLDFlags := os.Getenv("CGO_LDFLAGS")
    64  		cgoLDFlags += " -L " + libDir
    65  		if runtime.GOOS != "aix" {
    66  			cgoLDFlags += " -Wl,-rpath," + libDir
    67  		}
    68  		t.Logf("CGO_LDFLAGS=%s", cgoLDFlags)
    69  		os.Setenv("CGO_LDFLAGS", cgoLDFlags)
    70  
    71  	}
    72  
    73  	// Do a test build that doesn't involve Go FORTRAN support.
    74  	fcArgs := append([]string{"testdata/helloworld/helloworld.f90", "-o", "/dev/null"}, fcExtra...)
    75  	t.Logf("%s %s", fc, fcArgs)
    76  	if err := exec.Command(fc, fcArgs...).Run(); err != nil {
    77  		t.Skipf("skipping Fortran test: could not build helloworld.f90 with %s: %s", fc, err)
    78  	}
    79  
    80  	// Finally, run the actual test.
    81  	t.Log("go", "run", "./testdata/testprog")
    82  	var stdout, stderr strings.Builder
    83  	cmd := exec.Command(testenv.GoToolPath(t), "run", "./testdata/testprog")
    84  	cmd.Stdout = &stdout
    85  	cmd.Stderr = &stderr
    86  	err := cmd.Run()
    87  	t.Logf("%v", cmd)
    88  	if stderr.Len() != 0 {
    89  		t.Logf("stderr:\n%s", stderr.String())
    90  	}
    91  	if err != nil {
    92  		t.Errorf("%v\n%s", err, stdout.String())
    93  	} else if stdout.String() != "ok\n" {
    94  		t.Errorf("stdout:\n%s\nwant \"ok\"", stdout.String())
    95  	}
    96  }
    97  

View as plain text