github.com/atrn/dcc@v0.0.0-20220806184050-4470d2553272/link.go (about)

     1  // dcc - dependency-driven C/C++ compiler front end
     2  //
     3  // Copyright © A.Newman 2015.
     4  //
     5  // This source code is released under version 2 of the  GNU Public License.
     6  // See the file LICENSE for details.
     7  //
     8  
     9  package main
    10  
    11  import (
    12  	"fmt"
    13  	"os"
    14  	"path/filepath"
    15  	"strings"
    16  )
    17  
    18  // Link runs the compiler to link the given inputs and create the given
    19  // target using the supplied options. Return a corresponding error
    20  // value. If the target exists and is newer than any of the inputs no
    21  // linking occurs.
    22  func Link(target string, inputs []string, libs *Options, options *Options, otherFiles *Options, frameworks []string) error {
    23  	if target == "" {
    24  		target = platform.DefaultExecutable
    25  	}
    26  	link := func() error {
    27  		var args []string
    28  		args = append(args, options.Values...)
    29  		args = append(args, inputs...)
    30  		args = append(args, endash(libs.Values)...)
    31  		args = append(args, frameworks...)
    32  		args = append(args, ActualCompiler.DefineExecutableArgs(target)...)
    33  		if !Quiet {
    34  			if Verbose {
    35  				fmt.Fprintln(os.Stdout, ActualCompiler.Name(), strings.Join(args, " "))
    36  			} else {
    37  				fmt.Fprintln(os.Stdout, "ld", target)
    38  			}
    39  		}
    40  		return Exec(ActualCompiler.Name(), args, os.Stderr)
    41  	}
    42  	if IgnoreDependencies {
    43  		return link()
    44  	}
    45  	targetInfo, err := Stat(target)
    46  	if os.IsNotExist(err) {
    47  		return link()
    48  	}
    49  	if err != nil {
    50  		return err
    51  	}
    52  	if MostRecentModTime(options, libs).After(targetInfo.ModTime()) {
    53  		return link()
    54  	}
    55  	newestInput, err := NewestOf(inputs)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	if newestInput.After(targetInfo.ModTime()) {
    60  		return link()
    61  	}
    62  	if len(otherFiles.Values) > 0 {
    63  		newest, err := NewestOf(otherFiles.Values)
    64  		if err != nil {
    65  			return err
    66  		}
    67  		if newest.After(targetInfo.ModTime()) {
    68  			return link()
    69  		}
    70  	}
    71  	for _, name := range libs.Values {
    72  		if !strings.HasPrefix(name, "-l") {
    73  			if libInfo, err := Stat(name); err != nil {
    74  				return err
    75  			} else if FileIsNewer(libInfo, targetInfo) {
    76  				return link()
    77  			}
    78  		}
    79  	}
    80  	return nil
    81  }
    82  
    83  var standardPaths = make(StringSet)
    84  
    85  func endash(values []string) (dashed []string) {
    86  	if standardPaths.IsEmpty() {
    87  		for _, name := range platform.LibraryPaths {
    88  			standardPaths.Insert(name)
    89  		}
    90  	}
    91  	for _, name := range values {
    92  		dir, base := filepath.Dir(name), filepath.Base(name)
    93  		if standardPaths.Contains(dir) {
    94  			s := strings.TrimSuffix(base, platform.StaticLibSuffix)
    95  			if s == base {
    96  				s = strings.TrimSuffix(base, platform.DynamicLibSuffix)
    97  			}
    98  			t := strings.TrimPrefix(s, platform.StaticLibPrefix)
    99  			if t == s {
   100  				t = strings.TrimPrefix(s, platform.DynamicLibPrefix)
   101  			}
   102  			dashed = append(dashed, "-l"+t)
   103  		} else {
   104  			dashed = append(dashed, name)
   105  		}
   106  	}
   107  	return dashed
   108  }