1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
|
Notes for building binary distributions
=======================================
These notes are for those wishing to compile a binary distribution of Julia
for distribution on various platforms. We love users spreading Julia as
far and wide as they can, trying it out on as wide an array of
operating systems and hardware configurations as possible. As each
platform has specific gotchas and processes that must be followed in
order to create a portable, working Julia distribution, we have
separated most of the notes by OS.
Note that while the code for Julia is
[MIT-licensed, with a few exceptions](https://github.com/JuliaLang/julia/blob/master/LICENSE.md),
the distribution created by the techniques described herein will be
GPL licensed, as various dependent libraries such as `SuiteSparse` are
GPL licensed. We do hope to have a non-GPL distribution of Julia in the future.
Versioning and Git
------------------
The Makefile uses both the `VERSION` file and commit hashes and tags from the
git repository to generate the `base/version_git.jl` with information we use to
fill the splash screen and the `versioninfo()` output. If you for some reason
don't want to have the git repository available when building you should
pregenerate the `base/version_git.jl` file with:
make -C base version_git.jl.phony
Julia has lots of build dependencies where we use patched versions that has not
yet been included by the popular package managers. These dependencies will usually
be automatically downloaded when you build, but if you want to be able to build
Julia on a computer without internet access you should create a full-source-dist
archive with the special make target
make full-source-dist
that creates a julia-version-commit.tar.gz archive with all required dependencies.
When compiling a tagged release in the git repository, we don't display the
branch/commit hash info in the splash screen. You can use this line to show
a release description of up to 45 characters. To set this line you have
to create a Make.user file containing:
override TAGGED_RELEASE_BANNER = "my-package-repository build"
Target Architectures
--------------------
By default, Julia optimizes its system image to the native architecture of
the build machine. This is usually not what you want when building packages,
as it will make Julia fail at startup on any machine with incompatible CPUs
(in particular older ones with more restricted instruction sets).
We therefore recommend that you pass the `MARCH` variable when calling `make`,
setting it to the baseline target you intend to support. This will determine
the target CPU for both the Julia executable and libraries, and the system
image (the latter can also be set using `JULIA_CPU_TARGET`). Typically useful
values for x86 CPUs are `x86-64` and `core2` (for 64-bit builds) and
`pentium4` (for 32-bit builds). Unfortunately, CPUs older than Pentium 4
are currently not supported (see
[this issue](https://github.com/JuliaLang/julia/issues/7185)).
The full list of CPU targets supported by LLVM can be obtained by running
`llc -mattr=help`.
Linux
-----
On Linux, `make binary-dist` creates a tarball that contains a fully
functional Julia installation. If you wish to create a distribution
package such as a `.deb`, or `.rpm`, some extra effort is needed. See the
[julia-debian](https://github.com/staticfloat/julia-debian) repository
for an example of what metadata is needed for creating `.deb` packages
for Debian and Ubuntu-based systems. See the
[Fedora package](https://admin.fedoraproject.org/pkgdb/package/julia/)
for RPM-based distributions. Although we have not yet experimented
with it, [Alien](https://wiki.debian.org/Alien) could be used to
generate Julia packages for various Linux distributions.
Julia supports overriding standard installation directories via `prefix`
and other environment variables you can pass when calling `make` and
`make install`. See Make.inc for their list. `DESTDIR` can also be used
to force the installation into a temporary directory.
By default, Julia loads `$prefix/etc/julia/startup.jl` as an
installation-wide initialization file. This file can be used by
distribution managers to set up custom paths or initialization code.
For Linux distribution packages, if `$prefix` is
set to `/usr`, there is no `/usr/etc` to look into. This requires
the path to Julia's private `etc` directory to be changed. This can
be done via the `sysconfdir` make variable when building. Simply
pass `sysconfdir=/etc` to `make` when building and Julia will first
check `/etc/julia/startup.jl` before trying
`$prefix/etc/julia/startup.jl`.
OS X
----
To create a binary distribution on OSX, build Julia first, then cd to
`contrib/mac/app`, and run `make` with the same makevars that were used
with `make` when building Julia proper. This will then
create a `.dmg` file in the `contrib/mac/app` directory holding a
completely self-contained Julia.app.
Alternatively, Julia may be built as a framework by invoking `make` with the
`darwinframework` target and `DARWIN_FRAMEWORK=1` set. For example,
`make DARWIN_FRAMEWORK=1 darwinframework`.
Windows
-------
The best supported method of creating a Julia distribution on Windows
is to cross-compile from a Linux distribution such as Ubuntu. In-depth
compilation instructions [are
available](https://github.com/JuliaLang/julia/blob/master/README.windows.md).
However the important steps for redistribution are to ensure to `make
win-extras` in between `make` and `make binary-dist`. After that process is
completed, the `.zip` file created in the head Julia directory will
hold a completely self-contained Julia.
Notes on BLAS and LAPACK
------------------------
Julia builds OpenBLAS by default, which includes the BLAS and LAPACK
libraries. On 32-bit architectures, Julia builds OpenBLAS to use
32-bit integers, while on 64-bit architectures, Julia builds OpenBLAS
to use 64-bit integers (ILP64). It is essential that all Julia functions
that call BLAS and LAPACK API routines use integers of the correct width.
Most BLAS and LAPACK distributions provided on linux distributions,
and even commercial implementations ship libraries that use 32-bit
APIs. In many cases, a 64-bit API is provided as a separate library.
When using vendor provided or OS provided libraries, a `make` option
called `USE_BLAS64` is available as part of the Julia build. When doing
`make USE_BLAS64=0`, Julia will call BLAS and LAPACK assuming a 32-bit
API, where all integers are 32-bit wide, even on a 64-bit architecture.
Other libraries that Julia uses, such as SuiteSparse also
use BLAS and LAPACK internally. The APIs need to be consistent across
all libraries that depend on BLAS and LAPACK. The Julia build process
will build all these libraries correctly, but when overriding defaults
and using system provided libraries, this consistency must be ensured.
Also note that Linux distributions sometimes ship several versions of
OpenBLAS, some of which enable multithreading, and others only working
in a serial fashion. For example, in Fedora, `libopenblasp.so` is threaded,
but `libopenblas.so` is not. We recommend using the former for optimal
performance. To choose an OpenBLAS library whose name is different from
the default `libopenblas.so`, pass `LIBBLAS=-l$(YOURBLAS)` and
`LIBBLASNAME=lib$(YOURBLAS)` to `make`, replacing `$(YOURBLAS)` with the
name of your library. You can also add `.so.0` to the name of the library
if you want your package to work without requiring the unversioned `.so`
symlink.
Finally, OpenBLAS includes its own optimized version of LAPACK. If you
set `USE_SYSTEM_BLAS=1` and `USE_SYSTEM_LAPACK=1`, you should also set
`LIBLAPACK=-l$(YOURBLAS)` and `LIBLAPACKNAME=lib$(YOURBLAS)`. Else, the
reference LAPACK will be used and performance will typically be much lower.
Compilation scripts
===================
The [julia-nightly-packaging](https://github.com/staticfloat/julia-nightly-packaging)
repository contains multiple example scripts to ease the creation of
binary packages. It also includes miscellaneous tools to do things such as
fetching the last good commit that passed the
[Travis](https://travis-ci.org/JuliaLang/julia/builds) tests.
# Point releasing 101
Creating a point/patch release consists of several distinct steps.
## Backporting commits
Some pull requests are labeled "backport pending x.y", e.g. "backport pending 0.6".
This designates that the next subsequent release tagged from the release-x.y branch
should include the commit(s) in that pull request.
Once the pull request is merged into master, each of the commits should be [cherry
picked](https://git-scm.com/docs/git-cherry-pick) to a dedicated branch that will
ultimately be merged into release-x.y.
### Creating a backports branch
First, create a new branch based on release-x.y.
The typical convention for Julia branches is to prefix the branch name with your
initials if it's intended to be a personal branch.
For the sake of example, we'll say that the author of the branch is Jane Smith.
```
git fetch origin
git checkout release-x.y
git rebase origin/release-x.y
git checkout -b js/backport-x.y
```
This ensures that your local copy of release-x.y is up to date with origin before
you create a new branch from it.
### Cherry picking commits
Now we do the actual backporting.
Find all merged pull requests labeled "backport pending x.y" in the GitHub web UI.
For each of these, scroll to the bottom where it says "someperson merged commit
`123abc` into `master` XX minutes ago".
Note that the commit name is a link; if you click it, you'll be shown the contents
of the commit.
If this page shows that `123abc` is a merge commit, go back to the PR page---we
don't want merge commits, we want the actual commits.
However, if this does not show a merge commit, it means that the PR was squash-merged.
In that case, use the git SHA of the commit, listed next to commit on this page.
Once you have the SHA of the commit, cherry-pick it onto the backporting branch:
```
git cherry-pick -x -e <sha>
```
There may be conflicts which need to be resolved manually.
Once conflicts are resolved (if applicable), add a reference to the GitHub pull
request that introduced the commit in the body of the commit message.
After all of the relevant commits are on the backports branch, push the branch to
GitHub.
## Checking for performance regressions
Point releases should never introduce performance regressions.
Luckily the Julia benchmarking bot, Nanosoldier, can run benchmarks against any
branch, not just master.
In this case we want to check the benchmark results of js/backport-x.y against
release-x.y.
To do this, awaken the Nanosoldier from his robotic slumber using a comment on
your backporting pull request:
```markdown
@nanosoldier `runbenchmarks(ALL, vs=":release-x.y")`
```
This will run all registered benchmarks on release-x.y and js/backport-x.y and
produce a summary of results, marking all improvements and regressions.
If Nanosoldier finds any regressions, try verifying locally and rerun Nanosoldier
if necessary.
If the regressions are deemed to be real rather than just noise, you'll have to
find a commit on master to backport that fixes it if one exists, otherwise you
should determine what caused the regression and submit a patch (or get someone who
knows the code to submit a patch) to master, then backport the commit once that's
merged.
(Or submit a patch directly to the backport branch if appropriate.)
## Building test binaries
After the backport PR has been merged into the `release-x.y` branch, update your local
clone of Julia, then get the SHA of the branch using
```
git rev-parse origin/release-x.y
```
Keep that handy, as it's what you'll enter in the "Revision" field in the buildbot UI.
For now, all you need are binaries for Linux x86-64, since this is what's used for
running PackageEvaluator.
Go to https://buildog.julialang.org, submit a job for `nuke_linux64`, then queue up a
job for `package_linux64`, providing the SHA as the revision.
When the packaging job completes, it will upload the binary to the `julialang2` bucket
on AWS.
Retrieve the URL, as it will be used for PackageEvaluator.
## Checking for package breakages
Point releases should never break packages, with the possible exception of packages
that are doing some seriously questionable hacks using Base internals that are
not intended to be user-facing.
(In those cases, maybe have a word with the package author.)
Checking whether changes made in the forthcoming new version will break packages can
be accomplished using [PackageEvaluator](https://github.com/JuliaCI/PackageEvaluator.jl),
often called "PkgEval" for short.
PkgEval is what populates the status badges on GitHub repos and on pkg.julialang.org.
It typically runs on one of the non-benchmarking nodes of Nanosoldier and uses Vagrant
to perform its duties in separate, parallel VirtualBox virtual machines.
### Setting up PackageEvaluator
Clone PackageEvaluator and create a branch called `backport-x.y.z`, and check it out.
Note that the required changes are a little hacky and confusing, and hopefully that will
be addressed in a future version of PackageEvaluator.
The changes to make will be modeled off of
[this commit](https://github.com/JuliaCI/PackageEvaluator.jl/commit/5ba6a3b000e7a3793391d16f695c8704b91d6016).
The setup script takes its first argument as the version of Julia to run and the second
as the range of package names (AK for packages named A-K, LZ for L-Z).
The basic idea is that we're going to tweak that a bit to run only two versions of Julia,
the current x.y release and our backport version, each with three ranges of packages.
In the linked diff, we're saying that if the second argument is LZ, use the binaries
built from our backport branch, otherwise (AK) use the release binaries.
Then we're using the first argument to run a section of the package list: A-F for input
0.4, G-N for 0.5, and O-Z for 0.6.
### Running PackageEvaluator
To run PkgEval, find a hefty enough machine (such as Nanosoldier node 1), then run
```
git clone https://github.com/JuliaCI/PackageEvaluator.jl.git
cd PackageEvaluator.jl/scripts
git checkout backport-x.y.z
./runvagrant.sh
```
This produces some folders in the scripts/ directory.
The folder names and their contents are decoded below:
| Folder name | Julia version | Package range |
| :---------: | :-----------: | :-----------: |
| 0.4AK | Release | A-F |
| 0.4LZ | Backport | A-F |
| 0.5AK | Release | G-N |
| 0.5LZ | Backport | G-N |
| 0.6AK | Release | O-Z |
| 0.6LZ | Backport | O-Z |
### Investigating results
Once that's done, you can use `./summary.sh` from that same directory to produce
a summary report of the findings.
We'll do so for each of the folders to aggregate overall results by version.
```
./summary.sh 0.4AK/*.json > summary_release.txt
./summary.sh 0.5AK/*.json >> summary_release.txt
./summary.sh 0.6AK/*.json >> summary_release.txt
./summary.sh 0.4LZ/*.json > summary_backport.txt
./summary.sh 0.5LZ/*.json >> summary_backport.txt
./summary.sh 0.6LZ/*.json >> summary_backport.txt
```
Now we have two files, `summary_release.txt` and `summary_backport.txt`, containing
the PackageEvaluator test results (pass/fail) for each package for the two versions.
To make these easier to ingest into a Julia, we'll convert them into CSV files then
use the DataFrames package to process the results.
To convert to CSV, copy each .txt file to a corresponding .csv file, then enter Vim
and execute `ggVGI"<esc>` then `:%s/\.json /",/g`.
(You don't have to use Vim; this just is one way to do it.)
Now process the results with Julia code similar to the following.
```julia
using DataFrames
release = readtable("summary_release.csv", header=false, names=[:package, :release])
backport = readtable("summary_backport.csv", header=false, names=[:package, :backport])
results = join(release, backport, on=:package, kind=:outer)
for result in eachrow(results)
a = result[:release]
b = result[:backport]
if (isna(a) && !isna(b)) || (isna(b) && !isna(a))
color = :yellow
elseif a != b && occursin("pass", b)
color = :green
elseif a != b
color = :red
else
continue
end
printstyled(result[:package], ": Release ", a, " -> Backport ", b, "\n", color=color)
end
```
This will write color-coded lines to `stdout`.
All lines in red must be investigated as they signify potential breakages caused by the
backport version.
Lines in yellow should be looked into since it means a package ran on one version but
not on the other for some reason.
If you find that your backported branch is causing breakages, use `git bisect` to
identify the problematic commits, `git revert` those commits, and repeat the process.
## Merging backports into the release branch
After you have ensured that
* the backported commits pass all of Julia's unit tests,
* there are no performance regressions introduced by the backported commits as compared
to the release branch, and
* the backported commits do not break any registered packages,
then the backport branch is ready to be merged into release-x.y.
Once it's merged, go through and remove the "backport pending x.y" label from all pull
requests containing the commits that have been backported.
Do not remove the label from PRs that have not been backported.
The release-x.y branch should now contain all of the new commits.
The last thing we want to do to the branch is to adjust the version number.
To do this, submit a PR against release-x.y that edits the VERSION file to remove `-pre`
from the version number.
Once that's merged, we're ready to tag.
## Tagging the release
It's time!
Check out the release-x.y branch and make sure that your local copy of the branch is
up to date with the remote branch.
At the command line, run
```
git tag v$(cat VERSION)
git push --tags
```
This creates the tag locally and pushes it to GitHub.
After tagging the release, submit another PR to release-x.y to bump the patch number
and add `-pre` back to the end.
This denotes that the branch state reflects a prerelease version of the next point
release in the x.y series.
Follow the remaining directions in the Makefile.
## Signing binaries
Some of these steps will require secure passwords.
To obtain the appropriate passwords, contact Elliot Saba (staticfloat) or Alex Arslan
(ararslan).
Note that code signing for each platform must be performed on that platform (e.g. Windows
signing must be done on Windows, etc.).
### Linux
Code signing must be done manually on Linux, but it's quite simple.
First obtain the file `julia.key` from the CodeSigning folder in the `juliasecure` AWS
bucket.
Add this to your GnuPG keyring using
```
gpg --import julia.key
```
This will require entering a password that you must obtain from Elliot or Alex.
Next, set the trust level for the key to maximum.
Start by entering a `gpg` session:
```
gpg --edit-key julia
```
At the prompt, type `trust`, then when asked for a trust level, provide the maximum
available (likely 5).
Exit GnuPG.
Now, for each of the Linux tarballs that were built on the buildbots, enter
```
gpg -u julia --armor --detach-sig julia-x.y.z-linux-<arch>.tar.gz
```
This will produce a corresponding .asc file for each tarball.
And that's it!
### macOS
Code signing should happen automatically on the macOS buildbots.
However, it's important to verify that it was successful.
On a system or virtual machine running macOS, download the .dmg file that was built on
the buildbots.
For the sake of example, say that the .dmg file is called `julia-x.y.z-osx.dmg`.
Run
```
mkdir ./jlmnt
hdiutil mount -readonly -mountpoint ./jlmnt julia-x.y.z-osx.dmg
codesign -v jlmnt/Julia-x.y.app
```
Be sure to note the name of the mounted disk listed when mounting!
For the sake of example, we'll assume this is `disk3`.
If the code signing verification exited successfully, there will be no output from the
`codesign` step.
If it was indeed successful, you can detach the .dmg now:
```
hdiutil eject /dev/disk3
rm -rf ./jlmnt
```
If you get a message like
> Julia-x.y.app: code object is not signed at all
then you'll need to sign manually.
To sign manually, first retrieve the OS X certificates from the CodeSigning folder
in the `juliasecure` bucket on AWS.
Add the .p12 file to your keychain using Keychain.app.
Ask Elliot Saba (staticfloat) or Alex Arslan (ararslan) for the password for the key.
Now run
```
hdiutil convert julia-x.y.z-osx.dmg -format UDRW -o julia-x.y.z-osx_writable.dmg
mkdir ./jlmnt
hdiutil mount -mountpoint julia-x.y.z-osx_writable.dmg
codesign -s "AFB379C0B4CBD9DB9A762797FC2AB5460A2B0DBE" --deep jlmnt/Julia-x.y.app
```
This may fail with a message like
> Julia-x.y.app: resource fork, Finder information, or similar detritus not allowed
If that's the case, you'll need to remove extraneous attributes:
```
xattr -cr jlmnt/Julia-x.y.app
```
Then retry code signing.
If that produces no errors, retry verification.
If all is now well, unmount the writable .dmg and convert it back to read-only:
```
hdiutil eject /dev/disk3
rm -rf ./jlmnt
hdiutil convert julia-x.y.z-osx_writable.dmg -format UDZO -o julia-x.y.z-osx_fixed.dmg
```
Verify that the resulting .dmg is in fact fixed by double clicking it.
If everything looks good, eject it then drop the `_fixed` suffix from the name.
And that's it!
### Windows
Signing must be performed manually on Windows.
First obtain the Windows 10 SDK, which contains the necessary signing utilities, from
the Microsoft website.
We need the `SignTool` utility which should have been installed somewhere like
`C:\Program Files (x86)\Windows Kits\10\App Certification Kit`.
Grab the Windows certificate files from CodeSigning on `juliasecure` and put them
in the same directory as the executables.
Open a Windows CMD window, `cd` to where all the files are, and run
```
set PATH=%PATH%;C:\Program Files (x86)\Windows Kits\10\App Certification Kit;
signtool sign /f julia-windows-code-sign_2017.p12 /p "PASSWORD" ^
/t http://timestamp.verisign.com/scripts/timstamp.dll ^
/v julia-x.y.z-win32.exe
```
Note that `^` is a line continuation character in Windows CMD and `PASSWORD` is a
placeholder for the password for this certificate.
As usual, contact Elliot or Alex for passwords.
If there are no errors, we're all good!
## Uploading binaries
Now that everything is signed, we need to upload the binaries to AWS.
You can use a program like Cyberduck or the `aws` command line utility.
The binaries should go in the `julialang2` bucket in the appropriate folders.
For example, Linux x86-64 goes in `julialang2/bin/linux/x.y`.
Be sure to delete the current `julia-x.y-latest-linux-<arch>.tar.gz` file and replace
it with a duplicate of `julia-x.y.z-linux-<arch>.tar.gz`.
We also need to upload the checksums for everything we've built, including the source
tarballs and all release binaries.
This is simple:
```
shasum -a 256 julia-x.y.z* | grep -v -e sha256 -e md5 -e asc > julia-x.y.z.sha256
md5sum julia-x.y.z* | grep -v -e sha256 -e md5 -e asc > julia-x.y.z.md5
```
Note that if you're running those commands on macOS, you'll get very slightly different
output, which can be reformatted by looking at an existing file.
Mac users will also need to use `md5 -r` instead of `md5sum`.
Upload the .md5 and .sha256 files to `julialang2/bin/checksums` on AWS.
Ensure that the permissions on AWS for all uploaded files are set to "Everyone: READ."
For each file we've uploaded, we need to purge the Fastly cache so that the links on
the website point to the updated files.
As an example:
```
curl -X PURGE https://julialang-s3.julialang.org/bin/checksums/julia-x.y.z.sha256
```
Sometimes this isn't necessary but it's good to do anyway.
|