-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Build server produces dynamic linked executable #175
Comments
A go1.4.2 toolchain on debian 8 x64 also produces a dynamically linked executable. This change in output is recent. j@bca297cfcf52: |
It's a bug in the build process. Been doing some digging since our conversation on Twitter. Apparently this has been kind of a mess between Go 1.3 and Go 1.5 (not yet released). See golang/go#9369 and golang/go#9344 especially. Turns out this command, with Go 1.4, builds static binaries:
Looks like this will be changing again in Go 1.5 later this year... but I'm still not sure exactly how. Anyway, I was able to build a static binary this way but I haven't tested it for correctness. Apparently some important things can break, like the x509 package or the net package, if it doesn't have the shared libraries (??). I need to look into this but the more who do, the better - please feel free to try if you're up to running that build command. Try it with the tls directive and basically see if you can get it to break due to being statically compiled. More info (some is outdated): https://groups.google.com/forum/#!topic/golang-nuts/Rw89bnhPBUI and https://groups.google.com/forum/#!topic/golang-nuts/dXyhD-XiW50 and https://groups.google.com/forum/#!msg/golang-dev/ajODMUyOhPI/l3Kh-hW3x5AJ |
Ah, yes. I remember this now -- 1.4 broke what you'd do with net importers under 1.3 (and static linking has been kind of a mess on linux for always. It was the source of many wasted hours of kvetching on 9fans back in another lifetime.) Anyway I could have saved us some indirection if my memory were better -- I formerly had env vars setup for the netgo external build tagging and I forgot all about them. However, I always needed to combine the -tags dance with --ldflags options. I'm stepping through an attempt at building statically and testing this somewhat carefully now. We'll see if I learn anything. It is probably worth noting here (in hopes there will be none) that whatever bugs we find in a statically-linked linux x64 caddy will effect all of the caddy docker images I've seen, namely mine and @abiosoft 's. Our binaries are those from github/releases, which are statically linked. And also yes, the gomobile stuff for go1.5 has to dynamically link things for the build process enforced on especially android so this is set to become even less simple. |
one of the reasons I based my docker image on |
@abiosoft I understand your choice. However, in or outside of a container, due to both my product and my prejudices, I do not want any go program to be dynamically linked. Truly I don't want dynamic linking of any program whatsoever, but this broader indictment isn't intended to be flame bait -- dynamic linking is such a deeply held assumption that I don't think developers are often exposed to the arguments or, especially before golang, that there even was an argument to be made. Statically-linked programs still share code in the VM system with page mapping (provided you have an MMU), make distribution control much easier across architectures and levels of hardware-, OS-, and/or API- emulation/virtualization, cost essentially nothing at today's prices for RAM and disk, and completely elide a huge amount of complexity and security failures in the (always-privileged) linker layer of the operating system. Think of how bad this problem is on win32 -- all the versioning ends up sharing very little library code between 3rd-party applications using the "same" dll, but you do get a lot of complexity and subtle breakages for free. So maybe that is a very long way of saying it, but I don't want to effectively curate a minor linux distribution just to run an httpd. Currently, you don't need that distro, either, because you are shipping a statically-linked caddy in your docker image (as of your push today, v0.7.2 of caddy). Whichever way, static or dynamic, is really right for Caddy, I think the outcome of this bug should be knowing for sure how we're linking the binary, and linking it that way at any and all of the project's distribution points. |
I just noticed that you reported a 500 error when downloading for ARM Linux. I've found the cause:
Will fix that today. |
Yeah that was a second bug to this but I had already used so much bandwidth with my commentary on dynamic linking. I hope that didn't come off as a scold, but there is a lot of history leading to golang that, in short, relates very directly to why that compiler is called '5g'. -J
|
I fixed the 5g issue - builds should be working again. Next I'll look into compiling without cgo, see if anything breaks. If not, we're good to go and I can update the build server. Anyone else who wants to put it through the wringer is more than welcome... in fact it would be good to have many people testing it. |
I have not yet produced any problems that happen only in a static exe, fwiw. Catch me up -- where did with or without cgo come in? |
Sorry, to explain better: The reason some builds are not static is because there is some use of cgo in the standard library, which I wasn't aware of. So the net package, x509 package, and os/user package (although Caddy doesn't use that one, at least directly) cause a dynamic exe. Good to hear you haven't seen any problems yet. I haven't either. |
Ok right, roger, I get it. I.e., that thing we've been talking about this whole time. Thanks for all your time and discussion on this overnight and this morning, man. Beyond caddy, I learned/remembered things about the build chain I half-knew but hadn't fully percolated up out of my lizard brain until we arrived here. I actually think this set of unexpectednesses is going to get simpler for go users in 1.5 even tho it becomes more complex in the tools, if I read rsc right on several CRs. -J
|
This package README says:
However, I haven't yet seen any issues with DNS resolution or certificate access problems. Have you been able to get those to come out of hiding? (For example, I'm binding to a hostname "matt.dev" which is in my hosts file, so it should have to do a DNS lookup, right?) By the way, thanks very much for helping with this. |
It wouldn't do a DNS lookup, actually, because the resolver hits (If I were a better developer (person? ;) ), I'd be pushing some kind of tests at you instead of just pulling the old "oh yeah, I played with it" routine.) Being thorough here is actually a deeper set of issues than I knew. I'm going to see if I can find others talking about specific bugs encountered that are attributable to this "not ready for production" business. |
On the arm/5g build: Executable now exists. I fetched from caddyserver/downloads. Core only. It's a static executable. Stage one of that secondary distribution bug resolved. Tested (more on how below) and it LGTM. Testing:
That said, all these archs LGTM with static binaries, whether I build them or your build server does. I don't see bugs that exist only in the static builds. What does your test procedure for a user- (as opposed to function-level unit-), test of these potential issues look like, @abiosoft & @mholt? |
I just realised my base docker image So far, I've also had 0 issues with static binary. |
@abiosoft Out of curiosity, do you know why the dynamic executable fails there? Is the alpine base missing a library(s) entirely, or does it have the lib(s) but in a version that doesn't resolve all symbols? -J
|
@joshix I think its missing them. I did some search and I installed
Attempting to run it always gives
|
@abiosoft That last line means that the system on which you executed The system that built that I'm sure it's pretty obvious that my idea for this for our specific situation is to take advantage of one of golang's most simplifying abstractions, and always ship a statically-linked binary. This allows you the almost-magical power of actually shipping the actual code you actually built and actually tested. Your other option is to discover the exact libc against which a dynamically-linked One big motivation many devs have for using container systems like Docker is trying to solve this very problem: They no longer ship just their dynamically-linked binaries and hope customers have the correct library in the correct version. Instead they ship a container that includes the right library in the right version. I call this "poor-man's static linking". There are many good reasons for containers, but I think this particular reason is lousy -- for go developers, because we can link statically -- in fact in the simple case our tools always static link and don't even ask us about it. Static linking, by simply including the library code directly in the executable, does this job better and more simply than a container, wherein someone is curating a miniature linux distro just to get all the libs right. Sorry my comments are always so long. I would make them shorter if I had one or both of more intelligence or more time. :) |
@joshix Thanks for the education - I've been learning a lot about static compilation/linking lately. Today I will be trialling locally with a build server that produces only static binaries. |
I got static binaries building with the build server in a local VM, but I'm also experimenting with gb to make builds more stable, pending a bug fix. Stay tuned... hopefully will do a release this week either way. |
@joshix Would you give it a try now on the Caddy website? I deployed the changes and recompiled the standard library using CGO_ENABLED=0. Using that same env variable during builds produces static binaries (at least, with the current version of Go and from my own testing) - would you confirm and then feel free to close if fixed? |
@mholt Linux x64 is still a dynamically linked executable at caddyserver.com/download/. I grabbed caddy, no git selected, via browser download from caddyserver/download just now.
The linux arm and x86 binaries are statically linked as expected. |
Argh, I tried that same thing and it was static.... looking into it. |
@joshix Okay, I don't know why, but I had to run Or I'm going crazy. Please confirm. (That it's static now, not that I'm crazy.) |
@mholt LGTM now for Linux x64 binary from caddyserver/download:
|
👍 I've updated my setup script. Consider this case closed. Thanks for the report, patience, and efforts! |
https://caddyserver.com/download:
This should perhaps be filed against caddyserver/buildsrv, but this issue already exists, so reopening here. |
Ugh. How did this happen. I didn't change anything with the build process or the Go installation. Looking into it... |
Re-built the Go standard library. I see static executables now. Please try again and let me know. |
I still get a dynamic linux amd64 binary from https://caddyserver.com/download/build?os=linux&arch=amd64&features= In fact the exe has the same sha1 (a746fc6a1761df8a7d9548932c7efae6e8884a80) as I reported last back. Cached somewhere? When you “see static executables,” where are you looking that’s different from where I’m fetching binaries? I’ve let the buildsrv stuff remain pretty opaque to me so I’m not sure what the process looks like, nor how much trouble the effort to force-produce static binaries adds to it.
|
Oops, you're right. I forgot to clear the cache. * facepalm * Sorry for all the trouble about this. I'm considering programming a system test that will verify that the output is a static binary and have it run on a regular basis. Hopefully that will help pinpoint what causes them to turn into dynamic executables. |
Got it that time.
|
This URI:
https://caddyserver.com/download/build?os=linux&arch=amd64&features=
That is, caddy core, no git, linux x64 -- delivers a dynamically linked executable file.
linux x86 - static
linux x64 - dynamic
freebsd x64 - static
linux arm - 50x err
and those are the archs I can speak with any knowledge about and/or inspect.
@mholt indicates in conversation this departure from the usual & delicious go static binaries is not intentional.
The text was updated successfully, but these errors were encountered: