这是一个更普遍的问题,自从Swift成为开放源码,linux端口缺乏功能以来,这个问题就一直困扰着我。
有许多跨平台的编程语言。让我们以Go为例。(很棒的) Go标准库有很多包。有些是基于原始数据类型的有用的结构和函数。但是其他的实现了I/O、联网、操作系统和同步。
这与Swift和LLVM编译器infastructure相比如何?
对于clang,我认为存在跨平台并发性,我们可以交叉编译。但对于Swift来说,Mac版本依赖于"Darwin.C“,而Linux版本依赖于"Glibc”,这是平台上的差异。这导致了一些笨拙的代码片段:
#if os(Linux)
import Glibc
#else
import Darwin.C
#endif..。
#if os(Linux)
let j = Int(random() % (count - i)))) + i
#else
let j = Int(arc4random_uniform(UInt32(count - i))) + i
#endifSwift/LLVM是否总是在编译器的前端处理这些特定于平台的特性,以便它们依赖于c库?或者他们会不会将它们作为编译器的一部分来实现?
我读到Go/Rust编译器本身就是用Go/Rust编写的。这让我相信编译器在每个操作系统上的实现方式是不同的,以实现并发性、网络化--独立于c库。
是真地吗?或者是某些编程语言更擅长隐藏它们的依赖关系?
发布于 2016-03-29 00:44:45
这个问题可能会因为“过于宽泛”而结束。但是..。既然你用Go标记了它,我就用Go来回答它。
GoLang为每个平台都提供了一个编译器。Go运行时工具(go build等)是从相同的公共源代码/代码库中针对每个平台构建的。您可以看到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很丑陋..。嗯,Go实际上有一些干净的交叉编译C代码,使用上面的技巧更抽象和可管理。但是我以前的交叉编译的C代码,嗯,就是这么难看。
但是从Go 1.5开始,Go现在是用Go编写的。这意味着: Go运行时被用来将Go的源代码编译成Go运行时。这意味着Go语言使用它自己的平台特定指令来编译它自己的平台特定运行时。
Go如何指定平台
那么Go如何指定不同的特定于平台的代码呢?有两种不同的方式:
每种情况都有起伏。As stated by Dave Cheney himself
通常,在构建标记或文件后缀之间进行选择时,当平台或体系结构与要包含的文件完全匹配时,应选择文件后缀。
mypkg_linux.go // only builds on linux systems
mypkg_windows_amd64.go // only builds on windows 64bit platforms相反,如果您的文件适用于多个平台或体系结构,或者您需要排除特定平台,则应使用构建标记。例如,
% grep '+build' $HOME/go/src/pkg/os/exec/lp_unix.go
// +build darwin dragonfly freebsd linux netbsd openbsd构建在所有类unix平台上。
% grep '+build' $HOME/go/src/pkg/os/types_notwin.go // +build
!windows可以在除Windows之外的所有平台上构建。
如何编写跨平台的Go代码
如果你正在寻找一个关于如何为跨平台编写Go代码的模式,这是我的模式。您的里程可能会有所不同。
我个人尝试坚持使用文件后缀,因为只需查看文件列表,就可以更容易地指出哪些文件支持哪些平台。
首先,从API的接口开始。如果只有一个目的,则使用Be sure to follow Go's naming convention。
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)
}因为我没有导出接口,所以我没有加'er‘后缀。嗯,现在我想起来了,我应该这么做的。:)
现在,实现一个调用sh的Unix版本
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
}当为Unix操作系统编译这个包时,它将使用这个后缀为_unix.go的文件。然后,当可执行文件实际运行时,将调用init()并将unixshell{}结构实现连接起来。
这一切结合在一起,允许您编写一个平台无关的程序来使用这个包,并访问像这样的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)
}现在运行它:
$ go get github.com/eduncan911/go/pkg/cmd
$ go run main.go
Hello World!(免责声明,我只为该cmd实现了unix版本。下次我在Windows上测试它时,我会抛出一些powershell版本。)
GoLang的跨平台开发的简单性正是我转而选择Go的主要开发语言的原因,因为我有几个副项目,我希望成为跨平台的。
https://stackoverflow.com/questions/36263667
复制相似问题