I am attempting to build my haskell project on NixOS.
Running $ stack build gives the following error.
$ stack build
error: attribute ‘ghc822’ missing, at (string):1:53
(use ‘--show-trace’ to show detailed location information)
What does this error mean and how could I proceed? When I run $ stack build --show-trace as suggested, I get the following output, which I do not understand either.
$ stack build --show-trace
Invalid option `--show-trace'
Usage: stack build [TARGET] [--dry-run] [--pedantic] [--fast]
[--ghc-options OPTIONS] [--flag PACKAGE:[-]FLAG]
([--dependencies-only] | [--only-snapshot] |
[--only-dependencies]) ([--file-watch] | [--file-watch-poll])
[--exec CMD [ARGS]] [--only-configure] [--trace] [--profile]
[--no-strip] [--[no-]library-profiling]
[--[no-]executable-profiling] [--[no-]library-stripping]
[--[no-]executable-stripping] [--[no-]haddock]
[--haddock-arguments HADDOCK_ARGS] [--[no-]open]
[--[no-]haddock-deps] [--[no-]haddock-internal]
[--[no-]haddock-hyperlink-source] [--[no-]copy-bins]
[--[no-]copy-compiler-tool] [--[no-]prefetch]
[--[no-]keep-going] [--[no-]force-dirty] [--[no-]test]
[--[no-]rerun-tests] [--ta|--test-arguments TEST_ARGS]
[--coverage] [--no-run-tests] [--[no-]bench]
[--ba|--benchmark-arguments BENCH_ARGS] [--no-run-benchmarks]
[--[no-]reconfigure] [--[no-]cabal-verbose]
[--[no-]split-objs] [--skip ARG] [--help]
Build the package(s) in this directory/configuration
I tried changing my channel to nixos-17.09 instead of nixos-unstable (and running nix-channel --update), but still get the same error.
Output of $ nix-channel --list is shown below.
$ nix-channel --list
stack https://nixos.org/channels/nixos-17.09
nixos https://nixos.org/channels/nixos-17.09
The output of $ nix-env -qaPA 'nixos.haskell.compiler' shows ghc822 to be found.
$ nix-env -qaPA 'nixos.haskell.compiler'
warning: name collision in input Nix expressions, skipping ‘/home/matthew/.nix-defexpr/channels_root/nixos’
nixos.haskell.compiler.ghc6102Binary ghc-6.10.2-binary
nixos.haskell.compiler.ghc704 ghc-7.0.4
nixos.haskell.compiler.ghc704Binary ghc-7.0.4-binary
nixos.haskell.compiler.ghc7102 ghc-7.10.2
nixos.haskell.compiler.integer-simple.ghc7102 ghc-7.10.2
nixos.haskell.compiler.ghc7103 ghc-7.10.3
nixos.haskell.compiler.integer-simple.ghc7103 ghc-7.10.3
nixos.haskell.compiler.integer-simple.ghc742 ghc-7.4.2
nixos.haskell.compiler.ghc742 ghc-7.4.2
nixos.haskell.compiler.ghc742Binary ghc-7.4.2-binary
nixos.haskell.compiler.ghc763 ghc-7.6.3
nixos.haskell.compiler.ghc783 ghc-7.8.3
nixos.haskell.compiler.integer-simple.ghc783 ghc-7.8.3
nixos.haskell.compiler.ghc784 ghc-7.8.4
nixos.haskell.compiler.integer-simple.ghc784 ghc-7.8.4
nixos.haskell.compiler.ghc801 ghc-8.0.1
nixos.haskell.compiler.integer-simple.ghc801 ghc-8.0.1
nixos.haskell.compiler.ghc802 ghc-8.0.2
nixos.haskell.compiler.integer-simple.ghc802 ghc-8.0.2
nixos.haskell.compiler.integer-simple.ghc821 ghc-8.2.1
nixos.haskell.compiler.ghc821 ghc-8.2.1
nixos.haskell.compiler.integer-simple.ghc822 ghc-8.2.2
nixos.haskell.compiler.ghc822 ghc-8.2.2
nixos.haskell.compiler.integer-simple.ghcHEAD ghc-8.3.20170808
nixos.haskell.compiler.ghcHEAD ghc-8.3.20170808
nixos.haskell.compiler.ghcjs ghcjs-0.2.0
nixos.haskell.compiler.ghcjsHEAD ghcjs-0.2.020170323
nixos.haskell.compiler.jhc jhc-0.8.2
nixos.haskell.compiler.uhc uhc-1.1.9.4
I installed ghc8.2.2 via $ nix-env -iA nixos.haskell.compiler.ghc822, and $ ghc --version now returns
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.2.2
However, I still get the error error: attribute ‘ghc822’ missing, at (string):1:54 when attempting to run $ stack build.
Also, I attempted to see what ghc version my stack is using after this install, and this led to the same attribute ‘ghc822’ missing error.
$ stack ghc -- --version
error: attribute ‘ghc822’ missing, at (string):1:54
(use ‘--show-trace’ to show detailed location information)
It seems like your stack wants to retrieve the haskell.packages.ghc822 attribute or perhaps haskell.compiler.ghc822, which is not present in your version of <nixpkgs>.
Please check your channel configuration using sudo nix-channel --list (NixOS) or nix-channel --list. Releases 17.03 and older do not have this attribute. 17.09 and unstable should be fine. To switch your default <nixpkgs> to 17.09, note the name of the channel and run
nix-channel --add https://nixos.org/channels/nixos-17.09 <NAME>
Also run nix-channel --update to make sure you have a recent version. GHC 8.2.2 was added on Oct 31st.
If you don't want to change your channel configuration, I suppose you can set the NIX_PATH environment variable
NIX_PATH=nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/nixos-unstable.tar.gz stack build
Another option is to use a shell.nix. nixos-18.03 comes with ghc 8.2.2, so you can create a shell.nix like:
with import (builtins.fetchGit {
url = https://github.com/NixOS/nixpkgs-channels;
ref = "nixos-18.03";
rev = "cb0e20d6db96fe09a501076c7a2c265359982814";
}) {};
haskell.lib.buildStackProject {
name = "my-project";
buildInputs = [ ghc <otherlibs-here> ];
}
And add the following to your stack.yaml:
nix:
shell-file: shell.nix
Then stack build as usual.
You can provide an old GHC version using a shell.nix file place in the root of your project:
with import (fetchTarball https://github.com/NixOS/nixpkgs/archive/83b35508c6491103cd16a796758e07417a28698b.tar.gz) {};
let ghc = haskell.compiler.ghc802;
in haskell.lib.buildStackProject {
inherit ghc;
name = "myEnv";
buildInputs = [ pcre ];
}
Use a tar url from https://github.com/NixOS/nixpkgs/releases for a version of nixpkgs that contains the GHC version you need.
Then run nix-shell in the root of the project. This will put you into a shell in which you can perform stack build successfully since it would have access to the correct GHC version.
As palik commented, changing the resolver version -- in my case changing
resolver: lts-11.3
to
resolver: lts-9.1
in stack.yaml is a work-around. I do not know what the deeper issue is but would be interested to know.
Update: this post provides a thorough explanation with excellent tips on how to use stackage and nix in concert, including how to reach agreement between package versions of the stack resolver and nix channel.
How to know which resolver to specify in stack.yaml?
Go to this url, which shows stackage snapshots containing ghc:
https://www.stackage.org/package/ghc/snapshots
This will tell you the resolver corresponding to the ghc version you have. For example, I have ghc 8.10.7,
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.10.7
and doing a find '8.10.7' on that page shows me that corresponds to LTS Haskell 18.28 (ghc-8.10.7). So I would specify resolver: lts-18.28 in my stack.yaml.
(How to find resolvers for a given package was found in an answer here.)
based on #steve-chávez answer
stack.yaml
resolver: lts-13.19
system-ghc: true
install-ghc: false
nix:
enable: true
path: [nixpkgs=./nix/nixpkgs/default.nix]
shell-file: shell.nix
nix/nixpkgs/default.nix
let
spec = builtins.fromJSON (builtins.readFile ./revision.json);
src = import <nix/fetchurl.nix> {
url = "https://github.com/${spec.owner}/${spec.repo}/archive/${spec.rev}.tar.gz";
inherit (spec) sha256;
};
nixcfg = import <nix/config.nix>;
nixpkgs = builtins.derivation {
system = builtins.currentSystem;
name = "${src.name}-unpacked";
builder = builtins.storePath nixcfg.shell;
inherit src;
args = [
(builtins.toFile "builder" ''
$coreutils/mkdir $out
cd $out
$gzip -d < $src | $tar -x --strip-components=1
'')
];
coreutils = builtins.storePath nixcfg.coreutils;
tar = builtins.storePath nixcfg.tar;
gzip = builtins.storePath nixcfg.gzip;
};
in
import nixpkgs
nix/nixpkgs/update.sh
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p nix curl jq
SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
owner="nixos"
repo="nixpkgs-channels"
rev="nixos-unstable"
full_rev=$(curl --silent https://api.github.com/repos/$owner/$repo/git/refs/heads/$rev | jq -r .object.sha)
echo "full_rev=$full_rev"
expected_sha=$(nix-prefetch-url https://github.com/$owner/$repo/archive/$full_rev.tar.gz)
cat >"$SCRIPT_DIR/revision.json" <<EOL
{
"owner": "$owner",
"repo": "$repo",
"rev": "$full_rev",
"sha256": "$expected_sha"
}
EOL
shell.nix
{
#
# there are 2 ways of using stack with nix
# - define custom packages in `stack.yaml` `packages` option (https://docs.haskellstack.org/en/stable/nix_integration/#additions-to-your-stackyaml)
# - define custom package in `shell.nix` AND `shell-file: ...` in `stack.yaml` (https://docs.haskellstack.org/en/stable/nix_integration/#additions-to-your-stackyaml)
#
# we are using second option
ghc # stack expect this file to define a function of exactly one argument that should be called ghc
}:
let
# pkgs = import ./nix/nixpkgs/default.nix {}
pkgs = import <nixpkgs> {};
in
with pkgs;
haskell.lib.buildStackProject {
inherit ghc;
name = "myEnv";
buildInputs = [ cabal-install ];
}
Related
How can one get a list of all environments that use a certain package in conda?
conda search
Since Conda v 4.5.0, the conda search command has had an --envs flag for searching local environments for installed packages. See conda search -h:
--envs Search all of the current user's environments. If run
as Administrator (on Windows) or UID 0 (on unix),
search all known environments on the system.
A use case given in the original Issue was finding environments with outdated versions of openssl packages:
conda search --envs 'openssl<1.1.1l'
Conda Python API
Here's an example of how to do it with the Conda Python package (run this in base environment):
import conda.gateways.logging
from conda.core.envs_manager import list_all_known_prefixes
from conda.cli.main_list import list_packages
from conda.common.compat import text_type
# package to search for; this can be a regex
PKG_REGEX = "pymc3"
for prefix in list_all_known_prefixes():
exitcode, output = list_packages(prefix, PKG_REGEX)
# only print envs with results
if exitcode == 0 and len(output) > 3:
print('\n'.join(map(text_type, output)))
This works as of Conda v4.10.0, but there since it relies on internal methods, there's no guarantee going forward. Perhaps this should be a feature request, say for a CLI command like conda list --any.
Script Version
Here is a version that uses arguments for package names:
conda-list-any.py
#!/usr/bin/env conda run -n base --no-capture-output python
## Usage: conda-list-any.py [PACKAGE ...]
## Example: conda-list-any.py numpy pandas
import conda.gateways.logging
from conda.core.envs_manager import list_all_known_prefixes
from conda.cli.main_list import list_packages
from conda.common.compat import text_type
import sys
for pkg in sys.argv[1:]:
print("#"*80)
print("# Checking for package '%s'..." % pkg)
n = 0
for prefix in list_all_known_prefixes():
exitcode, output = list_packages(prefix, pkg)
if exitcode == 0 and len(output) > 3:
n += 1
print("\n" + "\n".join(map(text_type, output)))
print("\n# Found %d environment%s with '%s'." % (n, "" if n == 1 else "s", pkg))
print("#"*80 + "\n")
The shebang at the top should ensure that it will run in base, at least on Unix/Linux systems.
I've ran into the same issue and constructed a Powershell script that:
takes a regex query as an argument
goes through all available conda environments (and shows a progress bar while doing so)
lists all packages in each environment
returns the environments that have a package that match the query
per returned environment shows the package name that matched the query
The script is available at the bottom of this answer. I have saved it in a folder that is avaialble in the PATH under the name search-pkg-env.ps1.
The script can be run as follows (here I search for environments with the pip package pymupdf):
PS > search-pkg-env.ps1 pymupdf
Searching 19 conda environments...
py39
- pymupdf 1.18.13
Script
if ($args.Length -eq 0) {
Write-Host "Please specify a search term for that matches the package name (regex)." -BackgroundColor DarkYellow -ForegroundColor White
exit
}
$pkg_regex = $args[0]
$conda_envs = ConvertFrom-JSON -InputObject $([string]$(conda env list --json))
$total = $conda_envs.envs.Count
Write-Host "Searching $total conda environments..."
$counter = 1
ForEach ($conda_env in $conda_envs.envs) {
if ($total -gt 0) {
$progress = $counter / $total * 100
}
else {
$progress = 0
}
# Split the full path into its elements
$parts = $conda_env -Split '\\'
# The last element has the env name
$env_name = $parts[-1]
Write-Progress -Activity "Searching conda environment $env_name for $pkg_regex" -PercentComplete $progress
# Now search the provided package name in this environment
$search_results = ConvertFrom-JSON -InputObject $([string]$(conda list $pkg_regex -n $env_name --json))
If ($search_results.Count -gt 0) {
Write-Host $env_name
foreach ($result in $search_results) {
$pkg_name = $result.name
$pkg_version = $result.version
Write-Host " - $pkg_name $pkg_version"
}
}
$counter++
}
Python + Terminal solution
Jump directly to solution:
Use the following Github script Listing Environments Containing a Set of Packages
You Don't Need to install any Library
Simply copy the script, run and provide the set of packages needed (one or more)
From Scratch Solution:
To find all environments that contains a set of packages (one or more):
Get all the conda environments using Popen and conda env list; this will list all conda envs on your station.
Loop over the packages and check if a package exist in a conda env using Popen and conda list -n <environment>; this will list all available packages in an environment
Check through the output if it exists using either grep, findstr or your platform alternative on the terminal output - or do the search with python.
For each package save in a list
Check through lists for common environments and Voila!
On Ubuntu 14.04
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.3 LTS
Release: 14.04
Codename: trusty
Building a Yocto Poky image using the fido branch
inherit core-image
IMAGE_FEATURES += "x11-base x11-sato package-management ssh-server-dropbear"
IMAGE_INSTALL += "chromium \
lsb \
kernel-modules \
alsa-utils \
... and I am getting this sort of message
I look like it related to the Chromium recipe /meta-browser/recipes-browser/chromium/chromium_45.0.2454.85.bb which starts as such
include chromium.inc
DESCRIPTION = "Chromium browser"
DEPENDS += "libgnome-keyring"
and I get this message
ERROR: Logfile of failure stored in: /home/joel/yocto/build-fido/tmp/work/cortexa7hf-vfp-vfpv4-neon-poky-linux-gnueabi/chromium/45.0.2454.85-r0/temp/log.do_configure.28622
Log data follows:
| DEBUG: Executing python function sysroot_cleansstate
| DEBUG: Python function sysroot_cleansstate finished
| DEBUG: Executing shell function do_configure
| Updating projects from gyp files...
| Package xkbcommon was not found in the pkg-config search path.
| Perhaps you should add the directory containing `xkbcommon.pc'
| to the PKG_CONFIG_PATH environment variable
| No package 'xkbcommon' found
| gyp: Call to 'pkg-config --cflags xkbcommon' returned exit status 1.
| WARNING: exit code 1 from a shell command.
What I have tried
Installed the library
$ sudo apt-get install libxkbcommon-x11-dev
Search for xkbcommon.pc
$ apt-file search xkbcommon.pc
libxkbcommon-dev: /usr/lib/x86_64-linux-gnu/pkgconfig/xkbcommon.pc
pkg-config
joel#linux-Lenovo-G50-70:~/yocto/build-fido$ pkg-config --cflags xkbcommon
<=== Return is EMPTY (?)
joel#linux-Lenovo-G50-70:~/yocto/build-fido$ pkg-config --libs xkbcommon
-lxkbcommon <=== Looks correct
Added PKG_CONFIG_PATH
$ PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/x86_64-linux-gnu/pkgconfig/
$ export PKG_CONFIG_PATH
$ env | grep PKG
PKG_CONFIG_PATH=:/usr/lib/x86_64-linux-gnu/pkgconfig/
but I am still getting the same message when running bitbake
Any suggestions?
Find xkbcommon
$ find /usr/lib/ -name *xkbcommon*
/usr/lib/x86_64-linux-gnu/libxkbcommon.so
/usr/lib/x86_64-linux-gnu/libxkbcommon.so.0.0.0
/usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so.0.0.0
/usr/lib/x86_64-linux-gnu/libxkbcommon-x11.a
/usr/lib/x86_64-linux-gnu/libxkbcommon.a
/usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so.0
/usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so
/usr/lib/x86_64-linux-gnu/pkgconfig/xkbcommon.pc
/usr/lib/x86_64-linux-gnu/pkgconfig/xkbcommon-x11.pc
/usr/lib/x86_64-linux-gnu/libxkbcommon.so.0
In this case, it was the chromium recipe that failed to find libxkbcommon. As the error occurred when building a recipe for the target system, we need to tell the build system that the chromium recipe has a dependency on libxkbcommmon.
This can be done by adding
DEPENDS += "libxkbcommon"
to the chromium recipe.
It's worth noting, that libxkbcommon quite likely is an optional dependency, and in that case, it should be handled by a suitable PACKAGECONFIG. (See PACKAGECONFIG in ref.manual).
Note: I've never built chromium myself, thus I'd prefer to not suggest any suitable PACKAGECONFIG.
I think the Chromium_45 recipe is taken down since the last time I saw it (don't see it anymore).
Anyway, this is what I did to Chromium_40.
I have disabled Wayland (ozone-wayland in Chromium) so that it will only use x11.
In local.conf, I added
CHROMIUM_ENABLE_WAYLAND = "0"
By doing this, I will bypass CHROMIUM_WAYLAND_DEPENDS = "wayland libxkbcommon"
CHROMIUM_X11_DEPENDS = "xextproto gtk+ libxi libxss"
CHROMIUM_X11_GYP_DEFINES = ""
CHROMIUM_WAYLAND_DEPENDS = "wayland libxkbcommon"
CHROMIUM_WAYLAND_GYP_DEFINES = "use_ash=1 use_aura=1 chromeos=0 use_ozone=1"
python() {
if d.getVar('CHROMIUM_ENABLE_WAYLAND', True) == '1':
d.appendVar('DEPENDS', ' %s ' % d.getVar('CHROMIUM_WAYLAND_DEPENDS', True))
d.appendVar('GYP_DEFINES', ' %s ' % d.getVar('CHROMIUM_WAYLAND_GYP_DEFINES', True))
else:
d.appendVar('DEPENDS', ' %s ' % d.getVar('CHROMIUM_X11_DEPENDS', True))
d.appendVar('GYP_DEFINES', ' %s ' % d.getVar('CHROMIUM_X11_GYP_DEFINES', True))
}
P.S.: One more thing I found weird is use-egl.
PACKAGECONFIG[use-egl] = ",,virtual/egl virtual/libgles2" is overrided with PACKAGECONFIG[use-egl] = "" so I have removed PACKAGECONFIG[use-egl] = "" from chromium.inc
PACKAGECONFIG ??= "use-egl"
# this makes sure the dependencies for the EGL mode are present; otherwise, the configure scripts
# automatically and silently fall back to GLX
PACKAGECONFIG[use-egl] = ",,virtual/egl virtual/libgles2"
# Additional PACKAGECONFIG options - listed here to avoid warnings
PACKAGECONFIG[component-build] = ""
PACKAGECONFIG[disable-api-keys-info-bar] = ""
PACKAGECONFIG[ignore-lost-context] = ""
PACKAGECONFIG[impl-side-painting] = ""
PACKAGECONFIG[use-egl] = ""
PACKAGECONFIG[kiosk-mode] = ""
This is in my Makefile.core.def:
...
...
module = {
name = mymod;
common = net/mymod.c;
};
...
...
When I tried to build I get:
mv syminfo.lst.new syminfo.lst
cat syminfo.lst | sort | gawk -f /build/boot_project/src/grub/grub2/grub-core/genmoddep.awk > moddep.lst || (rm -f moddep.lst; exit 1)
grub_efi_get_variable in mymod is not defined
make[5]: *** [moddep.lst] Error 1
mymod.c has "#include <grub/efi/efi.h>" and tries to use "grub_efi_get_variable" function. I see that in syminfo.lst
> more syminfo.lst
...
undefined mymod grub_efi_get_variable
...
Can someone shed a light on the error and how to fix?
Thanks,
P.S I edited Makefile.core.def and Makefile.core.am in /build/boot_project/src/grub/grub2/grub-core/ to include my module and ran autogen.sh in /build/boot_project/src/grub/ to regenerate Makefile.in, then I ran dmake in /build/boot_project/src/grub/
Configuration was ran with --with-platform=efi. Anyhow, I noticed Makefile.core.am has all platform enabled for module mymod. So I edited Makefile.core.def to: module = { name = mymod; common = net/mymod.c; enable = efi}; After re-running autogen.sh, only platform with efi were added to Makefile.core.am and the build works.
Is it possible to increment a minor version number automatically each time a Go app is compiled?
I would like to set a version number inside my program, with an autoincrementing section:
$ myapp -version
MyApp version 0.5.132
Being 0.5 the version number I set, and 132 a value that increments automatically each time the binary is compiled.
Is this possible in Go?
The Go linker (go tool link) has an option to set the value of an uninitialised string variable:
-X importpath.name=value
Set the value of the string variable in importpath named name to
value.
Note that before Go 1.5 this option took two separate arguments.
Now it takes one argument split on the first = sign.
As part of your build process, you could set a version string variable using this. You can pass this through the go tool using -ldflags. For example, given the following source file:
package main
import "fmt"
var xyz string
func main() {
fmt.Println(xyz)
}
Then:
$ go run -ldflags "-X main.xyz=abc" main.go
abc
In order to set main.minversion to the build date and time when building:
go build -ldflags "-X main.minversion=`date -u +.%Y%m%d.%H%M%S`" service.go
If you compile without initializing main.minversion in this way, it will contain the empty string.
Use ldflags to set variables in main package:
With file main.go:
package main
import "fmt"
var (
version string
build string
)
func main() {
fmt.Println("version=", version)
fmt.Println("build=", build)
}
Then run:
go run \
-ldflags "-X main.version=1.0.0 -X main.build=12082019" \
main.go
Build:
go build -o mybinary \
-ldflags "-X main.version=1.0.0 -X 'main.build=$(date)'" \
main.go
Use ldflags to set variable in a non-main package:
With file config.go:
package config
import "fmt"
var (
Version string
)
func LogVersion() {
fmt.Println("version=", Version)
}
You will also need file main.go:
package main
import (
"fmt"
"github.com/user/repo/config"
}
func main() {
config.LogVersion()
}
Build your binary first:
go build -o mybinary main.go
Find the full path of variable name you want to set:
go tool nm <path_to_binary> | grep Version
Run and build the binary again but with the ldflags:
go run \
-ldflags "-X github.com/user/repo/config.Version=1.0.0" \
main.go --version
go build -o mybinary \
-ldflags "-X github.com/user/repo/config.Version=1.0.0" \
main.go
Inspired by https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable
Also if you are using goreleaser then read this https://goreleaser.com/environment/#using-the-mainversion :
Default wise GoReleaser sets three ldflags:
main.version: Current Git tag
main.commit: Current git commit SHA
main.date: Date according RFC3339
If you want to see this in action: https://github.com/hoto/fuzzy-repo-finder/blob/master/pkg/config/config.go
Additionally I would like to post a small example how to use git and a makefile:
--- Makefile ----
# This how we want to name the binary output
BINARY=gomake
# These are the values we want to pass for VERSION and BUILD
# git tag 1.0.1
# git commit -am "One more change after the tags"
VERSION=`git describe --tags`
BUILD=`date +%FT%T%z`
# Setup the -ldflags option for go build here, interpolate the variable values
LDFLAGS_f1=-ldflags "-w -s -X main.Version=${VERSION} -X main.Build=${BUILD} -X main.Entry=f1"
LDFLAGS_f2=-ldflags "-w -s -X main.Version=${VERSION} -X main.Build=${BUILD} -X main.Entry=f2"
# Builds the project
build:
go build ${LDFLAGS_f1} -o ${BINARY}_f1
go build ${LDFLAGS_f2} -o ${BINARY}_f2
# Installs our project: copies binaries
install:
go install ${LDFLAGS_f1}
# Cleans our project: deletes binaries
clean:
if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi
.PHONY: clean install
The make file will create two executables. One is executing function one, the other will take function two as main entry:
package main
import (
"fmt"
)
var (
Version string
Build string
Entry string
funcs = map[string]func() {
"f1":functionOne,"f2":functionTwo,
}
)
func functionOne() {
fmt.Println("This is function one")
}
func functionTwo() {
fmt.Println("This is function two")
}
func main() {
fmt.Println("Version: ", Version)
fmt.Println("Build Time: ", Build)
funcs[Entry]()
}
Then just run:
make
You will get:
mab#h2470988:~/projects/go/gomake/3/gomake$ ls -al
total 2020
drwxrwxr-x 3 mab mab 4096 Sep 7 22:41 .
drwxrwxr-x 3 mab mab 4096 Aug 16 10:00 ..
drwxrwxr-x 8 mab mab 4096 Aug 17 16:40 .git
-rwxrwxr-x 1 mab mab 1023488 Sep 7 22:41 gomake_f1
-rwxrwxr-x 1 mab mab 1023488 Sep 7 22:41 gomake_f2
-rw-rw-r-- 1 mab mab 399 Aug 16 10:21 main.go
-rw-rw-r-- 1 mab mab 810 Sep 7 22:41 Makefile
mab#h2470988:~/projects/go/gomake/3/gomake$ ./gomake_f1
Version: 1.0.1-1-gfb51187
Build Time: 2016-09-07T22:41:38+0200
This is function one
mab#h2470988:~/projects/go/gomake/3/gomake$ ./gomake_f2
Version: 1.0.1-1-gfb51187
Build Time: 2016-09-07T22:41:39+0200
This is function two
I had trouble using the -ldflags parameter when building my mixed command-line app and library project, so I ended up using a Makefile target to generate a Go source file containing my app's version and the build date:
BUILD_DATE := `date +%Y-%m-%d\ %H:%M`
VERSIONFILE := cmd/myapp/version.go
gensrc:
rm -f $(VERSIONFILE)
#echo "package main" > $(VERSIONFILE)
#echo "const (" >> $(VERSIONFILE)
#echo " VERSION = \"1.0\"" >> $(VERSIONFILE)
#echo " BUILD_DATE = \"$(BUILD_DATE)\"" >> $(VERSIONFILE)
#echo ")" >> $(VERSIONFILE)
In my init() method, I do this:
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s version %s\n", os.Args[0], VERSION)
fmt.Fprintf(os.Stderr, "built %s\n", BUILD_DATE)
fmt.Fprintln(os.Stderr, "usage:")
flag.PrintDefaults()
}
If you wanted an atomically-increasing build number instead of a build date, however, you would probably need to create a local file that contained the last build number. Your Makefile would read the file contents into a variable, increment it, insert it in the version.go file instead of the date, and write the new build number back to the file.
On Windows OS given the program below
package main
import "fmt"
var (
version string
date string
)
func main() {
fmt.Printf("version=%s, date=%s", version, date)
}
You can build using
go build -ldflags "-X main.version=0.0.1 -X main.date=%date:~10,4%-%date:~4,2%-%date:~7,2%T%time:~0,2%:%time:~3,2%:%time:~6,2%"
Date format assumes your environment echo %date% is Fri 07/22/2016 and echo %time% is 16:21:52.88
Then the output will be: version=0.0.1, date=2016-07-22T16:21:52
to use multi -ldflags:
$ go build -ldflags "-X name1=value1 -X name2=value2" -o path/to/output
Building on the other answers, with recent go versions it's also possible to write a buildid to an ELF section - though that's not so easily readable from within the program.
I write the same value to both, using something like the following:
BuildInfo:= "BUILD #x, branch # rev built yymmdd hh:mm:ss"
// note the nested quotes "''" required to get a string with
// spaces passed correctly to the underlying tool
ldFl := fmt.Sprintf("-X 'main.buildId=%s' -s -w '-buildid=%s'", BuildInfo, BuildInfo)
args := []string{
"build",
"-ldflags", ldFl,
"-trimpath",
"-gcflags", "-dwarf=false",
}
buildpath:="path/to/my/cmd"
args=append(args,buildpath)
buildCmd:=exec.Command("go", args...)
I use this with mage, a build tool written in go. You don't need the extra flags above, but I chose those to strip as much information as possible from release binaries.
(off topic: Mage requires a bit more upfront work than something like Make, but is much easier to extend/maintain than a make-based build system - plus you don't have to switch mental gears between go and some other syntax.)
I have a Bash script that builds a string to run as a command
Script:
#! /bin/bash
matchdir="/home/joao/robocup/runner_workdir/matches/testmatch/"
teamAComm="`pwd`/a.sh"
teamBComm="`pwd`/b.sh"
include="`pwd`/server_official.conf"
serverbin='/usr/local/bin/rcssserver'
cd $matchdir
illcommando="$serverbin include='$include' server::team_l_start = '${teamAComm}' server::team_r_start = '${teamBComm}' CSVSaver::save='true' CSVSaver::filename = 'out.csv'"
echo "running: $illcommando"
# $illcommando > server-output.log 2> server-error.log
$illcommando
which does not seem to supply the arguments correctly to the $serverbin.
Script output:
running: /usr/local/bin/rcssserver include='/home/joao/robocup/runner_workdir/server_official.conf' server::team_l_start = '/home/joao/robocup/runner_workdir/a.sh' server::team_r_start = '/home/joao/robocup/runner_workdir/b.sh' CSVSaver::save='true' CSVSaver::filename = 'out.csv'
rcssserver-14.0.1
Copyright (C) 1995, 1996, 1997, 1998, 1999 Electrotechnical Laboratory.
2000 - 2009 RoboCup Soccer Simulator Maintenance Group.
Usage: /usr/local/bin/rcssserver [[-[-]]namespace::option=value]
[[-[-]][namespace::]help]
[[-[-]]include=file]
Options:
help
display generic help
include=file
parse the specified configuration file. Configuration files
have the same format as the command line options. The
configuration file specified will be parsed before all
subsequent options.
server::help
display detailed help for the "server" module
player::help
display detailed help for the "player" module
CSVSaver::help
display detailed help for the "CSVSaver" module
CSVSaver Options:
CSVSaver::save=<on|off|true|false|1|0|>
If save is on/true, then the saver will attempt to save the
results to the database. Otherwise it will do nothing.
current value: false
CSVSaver::filename='<STRING>'
The file to save the results to. If this file does not
exist it will be created. If the file does exist, the results
will be appended to the end.
current value: 'out.csv'
if I just paste the command /usr/local/bin/rcssserver include='/home/joao/robocup/runner_workdir/server_official.conf' server::team_l_start = '/home/joao/robocup/runner_workdir/a.sh' server::team_r_start = '/home/joao/robocup/runner_workdir/b.sh' CSVSaver::save='true' CSVSaver::filename = 'out.csv' (in the output after "runnning: ") it works fine.
You can use eval to execute a string:
eval $illcommando
your_command_string="..."
output=$(eval "$your_command_string")
echo "$output"
I usually place commands in parentheses $(commandStr), if that doesn't help I find bash debug mode great, run the script as bash -x script
don't put your commands in variables, just run it
matchdir="/home/joao/robocup/runner_workdir/matches/testmatch/"
PWD=$(pwd)
teamAComm="$PWD/a.sh"
teamBComm="$PWD/b.sh"
include="$PWD/server_official.conf"
serverbin='/usr/local/bin/rcssserver'
cd $matchdir
$serverbin include=$include server::team_l_start = ${teamAComm} server::team_r_start=${teamBComm} CSVSaver::save='true' CSVSaver::filename = 'out.csv'
./me casts raise_dead()
I was looking for something like this, but I also needed to reuse the same string minus two parameters so I ended up with something like:
my_exe ()
{
mysql -sN -e "select $1 from heat.stack where heat.stack.name=\"$2\";"
}
This is something I use to monitor openstack heat stack creation. In this case I expect two conditions, an action 'CREATE' and a status 'COMPLETE' on a stack named "Somestack"
To get those variables I can do something like:
ACTION=$(my_exe action Somestack)
STATUS=$(my_exe status Somestack)
if [[ "$ACTION" == "CREATE" ]] && [[ "$STATUS" == "COMPLETE" ]]
...
Here is my gradle build script that executes strings stored in heredocs:
current_directory=$( realpath "." )
GENERATED=${current_directory}/"GENERATED"
build_gradle=$( realpath build.gradle )
## touch because .gitignore ignores this folder:
touch $GENERATED
COPY_BUILD_FILE=$( cat <<COPY_BUILD_FILE_HEREDOC
cp
$build_gradle
$GENERATED/build.gradle
COPY_BUILD_FILE_HEREDOC
)
$COPY_BUILD_FILE
GRADLE_COMMAND=$( cat <<GRADLE_COMMAND_HEREDOC
gradle run
--build-file
$GENERATED/build.gradle
--gradle-user-home
$GENERATED
--no-daemon
GRADLE_COMMAND_HEREDOC
)
$GRADLE_COMMAND
The lone ")" are kind of ugly. But I have no clue how to fix that asthetic aspect.
To see all commands that are being executed by the script, add the -x flag to your shabang line, and execute the command normally:
#! /bin/bash -x
matchdir="/home/joao/robocup/runner_workdir/matches/testmatch/"
teamAComm="`pwd`/a.sh"
teamBComm="`pwd`/b.sh"
include="`pwd`/server_official.conf"
serverbin='/usr/local/bin/rcssserver'
cd $matchdir
$serverbin include="$include" server::team_l_start="${teamAComm}" server::team_r_start="${teamBComm}" CSVSaver::save='true' CSVSaver::filename='out.csv'
Then if you sometimes want to ignore the debug output, redirect stderr somewhere.
For me echo XYZ_20200824.zip | grep -Eo '[[:digit:]]{4}[[:digit:]]{2}[[:digit:]]{2}'
was working fine but unable to store output of command into variable.
I had same issue I tried eval but didn't got output.
Here is answer for my problem:
cmd=$(echo XYZ_20200824.zip | grep -Eo '[[:digit:]]{4}[[:digit:]]{2}[[:digit:]]{2}')
echo $cmd
My output is now 20200824