J0-*_*nas 1 programming-languages llvm go swift
自从Swift成为开源并且linux端口缺乏费用以来,这更像是一个普遍的问题.
有许多跨平台编程语言.让我们以Go为例.(真棒)Go标准库有很多包.一些是基于原始数据类型的有用结构和函数.但其他人实现I/O,网络,操作系统和同步.
这与Swift和LLVM编译器基础结构相比如何?
对于clang我认为存在例如跨平台并发,我们可以交叉编译.但对于Swift来说,存在平台差异,其中Mac版本依赖于"Darwin.C"而Linux版本依赖于"Glibc".这导致一些尴尬的代码片段:
#if os(Linux)
import Glibc
#else
import Darwin.C
#endif
Run Code Online (Sandbox Code Playgroud)
...
#if os(Linux)
let j = Int(random() % (count - i)))) + i
#else
let j = Int(arc4random_uniform(UInt32(count - i))) + i
#endif
Run Code Online (Sandbox Code Playgroud)
Swift/LLVM是否总是在编译器的前端处理这些平台特定的功能,以便它们依赖于c库?或者他/他们会将它们作为编译器的一部分来实现吗?
我读到Go/Rust编译器本身是用Go/Rust编写的.这使我相信编译器的实现方式不同,每个操作系统都具有并发性,网络功能 - 独立于c库.
是这样吗?或者是一些编程语言更好地隐藏其依赖关系?
这个问题可能因"过于宽泛"而被关闭.但是......既然你用Go标记它,我就会回答Go.
GoLang为每个平台都有一个编译器.Go运行时工具(go build等)是针对每个平台而构建的,来自相同的公共源代码/ repo.您可以看到1.6支持的所有平台:
https://github.com/golang/go/tree/release-branch.go1.6/src/runtime
(记下_linux_amd64.go类型后缀.稍后详细介绍.)
现在,如何将代码编译到特定平台?这是每种语言对每个平台都有自己特定的指令(如果它是跨平台语言).在之前的Go(1.4及更早版本)中,运行时代码是用C语言编写的,具有特定于平台的C指令,类似于您已经提到的:
#if os(Linux)
import Glibc
#else
import Darwin.C
#endif
Run Code Online (Sandbox Code Playgroud)
这很丑陋......好吧,Go实际上有一些干净的交叉编译C代码,上面的技巧比较抽象和易于管理.但是我的旧交叉编译的C代码就像那样难看.
但是自从Go 1.5以来,Go现在用Go编写.这意味着:Go运行时用于将Go的源代码编译为Go运行时. 这意味着Go语言使用自己的特定于平台的指令来编译自己的平台特定运行时.
那么Go如何指定不同的平台特定代码?有两种不同的方式:
每个都有起伏. 正如Dave Cheney本人所说:
通常,在构建标记或文件后缀之间进行选择时,如果平台或体系结构与要包含的文件之间存在完全匹配,则应选择文件后缀.
mypkg_linux.go // only builds on linux systems
mypkg_windows_amd64.go // only builds on windows 64bit platforms
Run Code Online (Sandbox Code Playgroud)
相反,如果您的文件适用于多个平台或体系结构,或者您需要排除特定平台,则应使用构建标记.例如,
% grep '+build' $HOME/go/src/pkg/os/exec/lp_unix.go
// +build darwin dragonfly freebsd linux netbsd openbsd
Run Code Online (Sandbox Code Playgroud)
构建在所有类似unix的平台上.
% grep '+build' $HOME/go/src/pkg/os/types_notwin.go // +build
!windows
Run Code Online (Sandbox Code Playgroud)
构建在除Windows之外的所有平台上.
如果您正在寻找关于如何为跨平台编写Go代码的模式,这是我的模式.你的旅费可能会改变.
我个人尝试自己坚持使用文件后缀,因为只需查看文件列表就可以更容易地表示哪些文件支持哪个平台.
首先,从API的接口开始. 如果出于一个目的,请务必遵循Go的命名约定.
package cmd
// osshell is a global variable that is implement on a per-OS basis.
var osshell shell
// shell is the interface to an OS-agnostic shell to call commands.
type shell interface {
// Exec executes the command with the system's configured osshell.
Exec(command string) (string, error)
}
// Exec executes the command with the system's configured osshell.
func Exec(command string) (string, error) {
return osshell.Exec(command)
}
Run Code Online (Sandbox Code Playgroud)
由于我没有导出界面,因此我没有使用'er'后缀.呃,现在我想起来,我应该有.:)
现在,实现一个调用的Unix版本sh:
package cmd
import (
"bytes"
"os/exec"
)
func init() {
osshell = &unixshell{}
}
type unixshell struct {
}
func (s *unixshell) Exec(command string) (string, error) {
cmd := exec.Command("sh", "-c", command)
var buf bytes.Buffer
cmd.Stderr = &buf
cmd.Stdout = &buf
// assign return vars
err := cmd.Run()
out := buf.String()
return out, err
}
Run Code Online (Sandbox Code Playgroud)
在为Unix操作系统编译此程序包时,它将使用带有后缀的此文件_unix.go.然后,当可执行文件实际运行时,init()调用并连接unixshell{}struct实现.
这一切都汇集在一起,允许您编写一个平台无关的程序,它使用这个包并访问shell命令,如下所示:
package main
import (
"fmt"
"os"
"github.com/eduncan911/go/pkg/cmd"
)
func main() {
output, err := cmd.Exec("echo 'Hello World!'")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(output)
}
Run Code Online (Sandbox Code Playgroud)
现在运行它:
$ go get github.com/eduncan911/go/pkg/cmd
$ go run main.go
Hello World!
Run Code Online (Sandbox Code Playgroud)
(免责声明,我只为该cmd实现了一个unix版本.下次我在Windows上测试时,我会抛出一些powershell版本.)
GoLang易于跨平台开发正是我为什么切换到Go作为我的主要开发语言的原因,因为我有几个侧面项目我想要跨平台.
| 归档时间: |
|
| 查看次数: |
254 次 |
| 最近记录: |