Stack using binaries of other package - haskell

I have two projects in my user directory ~, the project A and B.
I run stack init and later stack build on the project A. Then, I have
the binaries of the A package in a folder ~/.stack-work/install/x86_64-linux/lts-6.0/7.10.3/bin. The issue is B needs this version of the binaries from A package, and then try the same build with stack on the B project directory. I tried on ~/B run the following command without success.
stack build ~/.stack-work/install/x86_64-linux/lts-6.0/7.10.3/bin
How can I do that? What if I create a third package C, and need something similar?
Excerpts:
The A.cabal content.
name: A
version: 1.1
And the B.cabal.
name: B
version: 1.0
build-depends: A>= 1.1
Then,
$ stack init
Looking for .cabal or package.yaml files to use to init the project.
Using cabal packages:
- B.cabal
Selecting the best among 8 snapshots...
* Partially matches lts-6.0
A version 1.0 found
- A requires ==1.1
This may be resolved by:
- Using '--omit-packages to exclude mismatching package(s).
- Using '--resolver' to specify a matching snapshot/resolver
But I actually have the version 1.1 of A build.

You don't need to include the project A's bin directory - that was a red herring.
Organize your files like this:
.
├── stack.yaml
├── project-A
│   ├── LICENSE.txt
│   ├── Setup.hs
│   ├── project-A.cabal
│   └── src
│   └── ...
│
└── project-B
   ├── Setup.hs
   ├── project-B.cabal
   └── src
   └── ...
Your top-level stack.yaml file will look like:
resolver: lts-5.13
packages:
- project-A/
- project-B/
Then in the top-level directory run stack build.

I'll take a stab at answering your question...
How about putting
~/.stack-work/install/x86_64-linux/lts-6.0/7.10.3/bin
in your PATH? If the other project really needs binaries (i.e. programs) built by another project, this would be the way to do it.
Or, copy the built programs to some directory in your current PATH - i.e. /usr/local/bin or ~/bin.
If this doesn't answer your question, please post the cabal files for both projects.

I found an answer after digging into the FAQ of stack. Create a file stack.yaml into B folder. At first the content could be:
resolver: lts-6.0
packages:
- '.'
- '/home/jonaprieto/A'
extra-deps: []
Then, it runs:
$ stack build

Related

Local crate not found when trying to update edition via cargo fix

Context:
I have a local C library called 'libmaths' that then uses Bindgen to create a 'libmaths-sys' crate that is locally stored in the same directory as my project.
Issue:
I want to use some of the features in the 2021 edition of Rust and currently my project is built off 2018. I am trying to update the project by following the instructions at:
https://doc.rust-lang.org/cargo/commands/cargo-fix.html
Run cargo fix --edition. Consider also using the --all-features flag if your project has multiple features. You may also want to run cargo
fix --edition multiple times with different --target flags if your
project has platform-specific code gated by cfg attributes.
Modify Cargo.toml to set the edition field to the new edition.
Run your project tests to verify that everything still works. If new
warnings are issued, you may want to consider running cargo fix again
(without the --edition flag) to apply any suggestions given by the
compiler.
To run cargo fix --edition I am told by the compiler to remove the edition="2018" in cargo toml. Following this I receive a compile error stating that libmaths-sys cannot be found. The code compiles and executes normally in 2018 but not without this edition tag.
I can not find anyone with a similar issue, this is my first stackoverflow question so not sure how best to show my code given its a context of a small project.
Error code
error[E0432]: unresolved import `libmaths_sys`
--> src/main.rs:1:5
|
1 | use libmaths_sys::*; // lib.rs in sys crate
| ^^^^^^^^^^^^ maybe a missing crate `libmaths_sys`?
File Structure and general overview of project
.
├── Cargo.lock
├── Cargo.toml
├── libmaths
│   ├── add.c
│   ├── add.h
│   └── subtract.c
├── libmaths-sys
│   ├── build.rs
│   ├── Cargo.lock
│   ├── Cargo.toml
│   ├── src
│   │   └── lib.rs
│   └── wrapper.h
├── README.md
└── src
  ├── lib.rs
  └── main.rs
libmaths contains add.c that returns a + b and subtract.c which returns a - b, with a header add.h directing to both .c files
The Rust code generated by bindgen is attached via lib.rs in the libmath-sys crate which links to the OUT DIR which I have omitted from the tree to save 200 lines of file names.
Try updating edition="2018" to edition="2021"; otherwise it defaults to edition="2015" which requires usage of extern crate.
As #Solomon Ucko directed me to, rustup update held the key.
Running rustup update produced:
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
info: syncing channel updates for '1.48-x86_64-unknown-linux-gnu'
info: checking for self-updates
stable-x86_64-unknown-linux-gnu unchanged - rustc 1.59.0 (9d1b2106e 2022-02-23)
1.48-x86_64-unknown-linux-gnu unchanged - rustc 1.48.0 (7eac88abb 2020-11-16)
info: cleaning up downloads & tmp directories
In the end, rustup was using the old 1.48 version and not the installed 1.59 version.
To switch to the newer vesion I ran:
rustup default stable
I then could follow the instructions from the link in the original question to change the edition.

Why is cargo build cache invalidating?

I have a barebones workspace project:
.
├── build-debug.sh
├── Cargo.lock
├── Cargo.toml
├── common
│   ├── Cargo.toml
│   └── src
│   └── lib.rs
├── rs-test.iml
├── server
│   ├── Cargo.toml
│   └── src
│   └── main.rs
└── wui
├── Cargo.toml
└── src
└── lib.rs
The rs files either empty or just an empty main function.
The server and the wui depends on common: common = { path = "../common" }.
The common project has one crates.io dependency with I suppose build script or proc macro dependency.
The build script:
cargo build -p wui --target wasm32-unknown-unknown
cargo build -p server
The problem:
When I rebuild the unchanged project, some wui dependencies are getting invalidated/rebuilt, then the same for server.
Either:
remove the wasm32 target flag
replace the dependency with a simple crate without build time compiled dependencies
It does not rebuild the subprojects anymore.
Is this a cargo bug? What can I do?
It's probably not a cargo bug. What is likely happening here is that your crates.io dependency (you don't mention what it is, which might have been useful) has different dependencies or features depending on the target architecture. Thus, as you alternate between building the WASM target and your host target, stuff is being rebuilt.
Perhaps it would be better in this case to stop using the Cargo workspace and build the server and wui separately; this way you'll have separate target directories for the server and wui, which takes some extra disk space and takes longer for non-incremental compilation, but will prevent you from having to rebuild that stuff all the time as you build both.

Importing a haskell module from the parent directory

Given the following directory structure:
root
├── scripts
│   └── script1.hs
└── source
   ├── librarymodule.hs
   └── libraryconfig.txt
Where "librarymodule.hs" would be a library exporting multiple functions, where the output is influenced by the contents of the libraryconfig.txt file in his directory.
script1.hs is the file needing to use the functions declared in librarymodule.hs.
I can't find a solution on the internet for a structure as given above and hoped someone could help out.
GHC has a -i option. Under root/scripts/, this will add root/source/ to the search path:
ghc -i../source script1.hs
Also consider packaging your library using cabal so you can install it and use it anywhere without worrying about paths.
Here is a minimal example of a library with data-files:
source/
├── mylibrary.cabal
├── LibraryModule.hs
└── libraryconfig.txt
mylibrary.cabal
name: mylibrary
version: 0.0.1
build-type: Simple
cabal-version: >= 1.10
data-files: libraryconfig.txt
library
exposed-modules: LibraryModule
other-modules: Paths_mylibrary
build-depends: base
default-language: Haskell2010
LibraryModule.hs
module LibraryModule where
import Paths_mylibrary -- This module will be generated by cabal
-- Some function that uses the data-file
printConfig :: IO ()
printConfig = do
n <- getDataFileName "libraryconfig.txt"
-- Paths_mylibrary.getDataFileName resolves paths for files associated with mylibrary
c <- readFile n
print c
See this link for information about the Paths_* module: https://www.haskell.org/cabal/users-guide/developing-packages.html#accessing-data-files-from-package-code
Now running cabal install should install mylibrary.
Then, under scripts/script1.hs, you can just run ghc script1.hs, using the library you installed.

Can I use Haskell's stack to compile and run _only_ the tests?

When I run a stack test or a stack test <package>:<test-suite> then the output looks something like:
package: configure (lib + exe + test)
package: build (lib + exe + test)
package: copy/register
package: test (suite: tests)
And it ends up basically compiling all my changes twice: once for the exe or lib and a second time for the test.
What I would like is a command like stack test --test-only that would produce something like:
package: configure (test)
package: build (test)
package: copy/register
package: test (suite: tests)
I have already looked through the available command line flags and stack documentation. I have also attempted a google search to see if anyone has talked about something similar.
So my questions are:
1. What is the best currently available way to compile and run only the tests? My best guess on this one is to try putting the tests in a separate cabal package.
2. Is there some reason why stack doesn't or couldn't do this?
I have made some experiments using stack build <pkgname>:test:<testsuite> and found nothing really pleasing when you have all your app/src/main in one directory cabal-project.
Now I did not investigate if this is an issue due to stack using Cabal as a library or whether this is a stack issue.
here are a few issues that might be related
Turning on test coverage rebuilds all packages #1940
stack ghci foo:test:bar uses library dependencies unless --test is passed #1845
Allow stack test to skip certain test suites #1659
How to specify a subset of tests to run? #2519
"stack test " does not run tests? #1961
But I guess you'd have to file a bug if noone provides a better answer.
A possible but quite ugly solution (in my opinion) is to split test-suite, app and library into separate cabal projects - here is the example folder structure I used for testing.
myproject
├── stackapp
│   ├── app
│   │   └── Main.hs
│   ├── ChangeLog.md
│   ├── LICENSE
│   ├── Setup.hs
│   └── stackapp.cabal
├── stacksrc
│   ├── ChangeLog.md
│   ├── LICENSE
│   ├── Setup.hs
│   ├── src
│   │   └── Lib.hs
│   └── stacksrc.cabal
├── stacktest
│   ├── ChangeLog.md
│   ├── LICENSE
│   ├── Setup.hs
│   ├── src
│   ├── stacktest.cabal
│   └── tst
│   └── Spec.hs
└── stack.yaml
stack.yaml
resolver: lts-7.3
packages:
- './stacksrc'
- './stacktest'
- './stackapp'
extra-deps: []
flags: {}
extra-package-dbs: []
Note that you need to include a "dummy" library section in order to make it compile, cabal is picky about cabal files that have neither lib nor exe part.
stacktest.cabal
...
library
-- dummy
build-depends: base >=4.9 && <4.10
hs-source-dirs: src
default-language: Haskell2010
test-suite tests
type: exitcode-stdio-1.0
main-is: Spec.hs
hs-source-dirs: tst
build-depends: base
, stacksrc
, hspec
, hspec-expectations-pretty-diff
default-language: Haskell2010
Then you can modify tests and run stack stacktests:test:tests without rebuilding the lib and/or the app part, but stack is intelligent enough designed to rebuild the lib part if you change it before you run the tests.
UPDATE
For future reference here is a link to the opened ticket:
To use stack to compile and run only the tests #2710

Debian Package Creation- How to install configuration files?

I've been really stuck on this minor (I'm sure) issue so any help would be greatly appreciated. I've created a standard ubuntu package with dh_make. The purpose of this package is to create a package that will set up all the ldap related packages that a system needs including it's configuration. One of the steps I'm trying to do is to copy over an /etc/ldap.conf file while making a backup of the existing file. How do I do this? I tried to create a postinst script that looks essentially like the following, but I'm not clear on how the package stores the files and I get an error saying missing etc/ldap.conf file. What's the best way to do this? Here is my postinst script:
#!/bin/bash -xv
install -v -b etc/ldap.conf /etc/ldap.conf > /tmp/tst 2>&1
Here is my skeleton structure:
root#hqd-clientb-16:~/navldapubuntu-0.1/debian# tree
├── changelog
├── compat
├── control
├── copyright
├── docs
├── etc
   └── ldap.conf
├── install
├── postinst
├── README.Debian
├── README.source
├── rules
├── source
   └── format
├── navldapubuntu
   └── etc
├── navldapubuntu.debhelper.log
├── navldapubuntu.dirs
└── navldapubuntu.doc-base.EX
Here's some additional information of the package I created.
dpkg --contents tnoldapubuntu_0.1-1_all.deb (truncated output)
./usr/
./usr/share/
./usr/share/doc
./usr/share/doc/navldapubuntu/
./usr/share/doc/navldapubuntu/copyright
./usr/share/doc/navldapubuntu/README.Debian
./usr/share/doc/navldapubuntu/changelog.Debian.gz
./etc/ldap.conf
There is a special tool that designed for creation of configuration packages: http://debathena.mit.edu/config-packages
Here is a simple template that could be helpful for a quick start.
List of files
template (directory)
template/debian (directory)
template/debian/control
template/debian/changelog
template/debian/displace
template/debian/rules
template/debian/postinst
template/debian/install
template/debian/docs
template/debian/compat
template/README
template/BUILD
template/files (directory)
template/files/etc/ldap.conf.mycompanyname
Content
template/debian/control:
Source: PACKAGE_NAME
Section: morpho/misc
Priority: optional
Maintainer: MAINTAINER
Build-Depends: debhelper, config-package-dev (>= 5.0~)
Package: PACKAGE_NAME
Architecture: all
Depends: ${misc:Depends}, DEPENDENCY [, DEPENDENCY ...]
Provides: ${diverted-files}
Conflicts: ${diverted-files}
Description: PACKAGE_DESCRIPTION_SHORT
PACKAGE_DESCRIPTION_LONG.
template/debian/displace
/etc/ldap/ldap.conf.mycompanyname
template/debian/install
files/* /
template/debian/postinst
#!/bin/sh
set -e
#DEBHELPER#
POSTINST_SCRIPT
template/debian/rules
#!/usr/bin/make -f
# Exclude *.svn* from building
# you probably don't need this if don't use SVN
export DH_ALWAYS_EXCLUDE=.svn
# Core (check http://debathena.mit.edu/config-packages for more information)
%:
dh $# --with=config-package
# Prevent dh_installdeb of treating files in /etc as configuration files
# you need this if need configuration files been always rewritten
# even if changed
override_dh_installdeb:
dh_installdeb
rm debian/*/DEBIAN/conffiles
template/debian/docs
README
BUILD
And finally you can build this package with the following command:
dpkg-buildpackage -us -uc -I.svn
You need to create a "conffiles" file in the DEBIAN directory, next to the "control" file, and declare /etc/ldap.conf in it. So this file will be automatically considered a configuration file, and changes to it will prompt a "new config file, would you want to overwrite, yadda yadda".

Resources