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":
    51  			libExt = "a"
    52  		}
    53  		libPath, err := exec.Command(fc, append([]string{"-print-file-name=libgfortran." + libExt}, fcExtra...)...).CombinedOutput()
    54  		if err != nil {
    55  			t.Errorf("error invoking %s: %s", fc, err)
    56  		}
    57  		libDir := filepath.Dir(string(libPath))
    58  		cgoLDFlags := os.Getenv("CGO_LDFLAGS")
    59  		cgoLDFlags += " -L " + libDir
    60  		if runtime.GOOS != "aix" {
    61  			cgoLDFlags += " -Wl,-rpath," + libDir
    62  		}
    63  		t.Logf("CGO_LDFLAGS=%s", cgoLDFlags)
    64  		os.Setenv("CGO_LDFLAGS", cgoLDFlags)
    65  
    66  	}
    67  
    68  	// Do a test build that doesn't involve Go FORTRAN support.
    69  	fcArgs := append([]string{"testdata/helloworld/helloworld.f90", "-o", "/dev/null"}, fcExtra...)
    70  	t.Logf("%s %s", fc, fcArgs)
    71  	if err := exec.Command(fc, fcArgs...).Run(); err != nil {
    72  		t.Skipf("skipping Fortran test: could not build helloworld.f90 with %s: %s", fc, err)
    73  	}
    74  
    75  	// Finally, run the actual test.
    76  	t.Log("go", "run", "./testdata/testprog")
    77  	var stdout, stderr strings.Builder
    78  	cmd := exec.Command("go", "run", "./testdata/testprog")
    79  	cmd.Stdout = &stdout
    80  	cmd.Stderr = &stderr
    81  	err := cmd.Run()
    82  	t.Logf("%v", cmd)
    83  	if stderr.Len() != 0 {
    84  		t.Logf("stderr:\n%s", stderr.String())
    85  	}
    86  	if err != nil {
    87  		t.Errorf("%v\n%s", err, stdout.String())
    88  	} else if stdout.String() != "ok\n" {
    89  		t.Errorf("stdout:\n%s\nwant \"ok\"", stdout.String())
    90  	}
    91  }
    92  

View as plain text