Debugging IO in a package module inside GHCi - debugging

I'm doing low-level IO (for library bindings) in Haskell and am experiencing a segfault. I would like to use GHCi's :break to figure out what's going on, but here's what happens:
> import SDL
> :break SDL.setPaletteColors
cannot set breakpoint on setPaletteColors: module SDL.Video.Renderer is not interpreted
Since the offending code is not inside my own modules, but rather inside a module in an external package, it's loaded as compiled code and apparently I can't use :break on compiled modules.
GHCi manual confirms this and provides a hint:
There is one major restriction: breakpoints and single-stepping are only available in interpreted modules; compiled code is invisible to the debugger[5].
[5] Note that packages only contain compiled code, so debugging a package requires finding its source and loading that directly.
Let's try it directly:
> :load some_path/sdl2/src/SDL/Video/Renderer.hs
some_path/sdl2/src/SDL/Video/Renderer.hs:101:8:
Could not find module ‘Control.Monad.IO.Class’
It is a member of the hidden package ‘transformers-0.3.0.0’.
Perhaps you need to add ‘transformers’ to the build-depends in your .cabal file.
Use -v to see a list of the files searched for.
I can add the dependencies to my .cabal file, but this already feels wrong. Once I've done that:
> :load some_path/sdl2/src/SDL/Video/Renderer.hs
some_path/sdl2/src/SDL/Video/Renderer.hs:119:8:
Could not find module ‘SDL.Internal.Numbered’
it is a hidden module in the package ‘sdl2-2.0.0’
Use -v to see a list of the files searched for.
I could make those modules public (probably? by modifying the package .cabal?), but at this point it seems a really awkward way to do things and I didn't pursue it further.
EDIT:
I actually tried that and got the baffling result:
> :load some_path/sdl2/src/SDL/Video/Renderer.hs
[1 of 1] Compiling SDL.Video.Renderer ( some_path/sdl2/src/SDL/Video/Renderer.hs, interpreted )
Ok, modules loaded: SDL.Video.Renderer.
> :break SDL.setPaletteColors
cannot set breakpoint on SDL.setPaletteColors: module SDL.Video.Renderer is not interpreted
My (uneducated) guess: it's because the external module is still linked to my code as a binary, and loading it dynamically in interpreted mode doesn't change that.
So, to sum up the question: what is a good way to debug IO in an external package?
Additional notes:
I do have the source to the package I need to debug; in fact, it's been added to the project with cabal sandbox add-source
An alternative option to using GHCi would be to add traces to the package source, but this is an unfortunate option, since it involves recompilation of the package on each modification (whenever I need more information about the execution and modify the traces), and that takes a really long time. Interactive debugging with GHCi seems a better tool for this job, if only I knew how to use it.

Stack has some support for this. Running stack ghci --load-local-deps $TARGET will load your project and any dependencies that are in the packages field of stack.yaml, including if they're marked as extra-deps. Breakpoints will work then. You can debug a dependency in GHCi by running stack unpack $PACKAGE and adding it to packages in stack.yaml.
This is not a panacea however. If the packages have conflicting package-global language extensions (or other dynamic flags) or module name clashes it won't work. For example, if your top-level package has default-extensions: NoImplicitPrelude and your dependencies don't, they won't have a prelude imported and will almost certainly not load. See this GHC bug.

Related

What's the idiomatic way to depend on module not referenced in code (mockgen specifically)?

I just switched all my existing projects to use modules. After running go mod init in each repo and adding my private personal dependencies, my go.mod looks like:
module bitbucket.org/XXXXX/my-app
replace bitbucket.org/XXXXX/utilities => ../utilities
go 1.15
require (
<auto-generated stuff>
)
Everything is working, except mock generation, since I don't actually import mockgen directly in my code (I run it through my Makefile).
I suppose I can add it to my require blob, and make sure my Makefile invokes go mod download explicitly before running it, but I worry that it will get clobbered by the go module manager. I figure go mod tidy in particular will nuke it since it's not referenced through the code it cares about.
What's the right way to do this? I assume go get is meant to be deprecated, so I can't keep using it as I do now.
A popular way of doing this is by creating a file with a build tag and doing underscore imports. See this example from grpc-gateway
// +build tools
package tools
import (
_ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway"
_ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger"
_ "github.com/golang/protobuf/protoc-gen-go"
)

Golang plugin on Intellij. Library and break points

I write my code on Go. I build my project in Idea Intellij with plugin for golang. I have a package main. In main import different packages.
import (
"RF"
"flag"
"io"
"net/http"
"os"
"runtime"
"depot"
"info"
"logger"
"logic"
"poly"
"ranker"
"revgeocoder"
"search"
"search/engine"
"stat"
"views"
"fmt"
)
This packages very well linked if I write paths in $GOPATH. In Idea Intellij it makes such way:
Now, I want:
Build my project without warning
Debugging my project
First point. I make a 'build' and than I have: "Package is not specified"
If I write to Package name main, than warning doesn't disappear:
What I can do?
Point number two. The assembly is successful. After that part of package I can debug, another package I cannot debug. For example package engine I can debug. Path to this package:
/home/INT.PV.KM/urvanov/hedgehogues/distr/mapsfullsearch/src/search/engine/engine.go
Next file I cannot debug.
/home/INT.PV.KM/urvanov/hedgehogues/distr/mapsfullsearch/src/search/context.go
I cannot set a breaks point in this file:
Please, help me with my problems.
Build my project without warning -> you need to use the full package name (for example you need to use "github.com/dlsniper/demo" for a package under the GOPATH /home/florin/go and full path $GOPATH/src/github.com/dlsniper/demo. Alternatively, you can use the Run Kind directory and point it to the directory or simply just use the green arrow near the func main, click on it, select Run ... and then select Go Application
Debugging my project -> once you get your Run Configuration of type Go Application to run the application then to debug it you'll just need to use the Debug option instead of Run. Alternatively, you can click on the green arrow near the func main and choose Debug... to debug your application.
The answer to the first question
Any project in Go consist of packages. There is nothing except for packages. All packages are located in the same directory, which one is project. Other directories are libraries. They set through environment variable $GOPATH. IDEA IntelliJ let make it as:
File->Settings:
There are two type of libs in Go: globals and locals. You read about this here.
In the build time is necessary to specify which package we want to gather and line up all the dependencies themselves. In my project, there are n packets. For example, I can build mapsfullsearch package. I can build mfsimporter package. Or I can build any other, in which there is func main () {/*...*/}. To build just specify the appropriate configuration.
After that, all Imports (if relevant packages exist), resolved.
About configurations. Go to Run -> Edit Configurations...
Name: name of compilled file.
Run kind: which type of building (file or package).
Package: package name that matches the name of the directory in which the main(). There are drop-down list in IDEA IntelliJ. It appears, if you start to write his name.
Output directory: directory where the binary.
Environments: variables of environments
Go Tool arguments: compiler's arguments
Program arguments: program's arguments
For more information about config can be read here.
The answer to the second question
In the IDEA may be poorly specified file path. In that case, to which I referred in her question, the problem was related to the fact that the path to the library is specified via the home directory, which is denoted by ~. IDEA does not perceive such format. Repeat this problem I did not succeed. Although up to the moment until I put the project in the root file system, my project didn't work.

How do packages with multiple files work in golang?

This repo has 3 go files all begin with "package lumber".
To use this package, I'm supposed to put this in my GOROOT and simply
import lumber
in my program. How do variables and types in this package connect with each other across multiple files? How does the go compiler know which file to begin reading first?
In case I want to read the package, where should I begin reading to understand the package? What exactly is the flow of things here?
To elaborate on jnml's answer:
When you use import "foo/bar" in your code, you are not referring to the source files (which will be located in $GOPATH/src/foo/bar/).
Instead, you are referring to a compiled package file at $GOPATH/pkg/$GOOS_$GOARCH/foo/bar.a. When you build your own code, and the compiler finds that the foo/bar package has not yet been compiled (or is out of date), it will do this for you automatically.
It does this by collating* all the relevant source files in the $GOPATH/src/foo/bar directory and building them into a single bar.a file, which it installs in the pkg directory. Compilation then resumes with your own program.
This process is repeated for all imported packages, and packages imported by those as well, all the way down the dependency chain.
*) How the files are collated, depends on how the file itself is named and what kind of build tags are present inside it.
For a deeper understanding of how this works, refer to the build docs.
No, you're not "supposed to put this in my GOROOT". You're supposed to execute
$ go get github.com/jcelliott/lumber
which will clone the repository into $GOPATH/src/github.com/jcelliott/lumber. Then you can use the package by importing it in your code as
import "github.com/jcelliott/lumber"
About the scoping rules: Declarations and scope

Boost's bjam is running tests before the build has finished

I have a fairly simple Boost.Python extension that I am building with bjam. The problem is that the order that things happen in doesn't make sense to me, and I can't see how to fix it.
My project consists of a root directory, with a Jamroot, and a single project subdirectory with a Jamfile, C++ file, header file, and Python script.
In the root I have a Jamroot file that looks like this, largely scraped together from examples and the docs. It is separate from the project's Jamfile because I actually want to share this amongst several projects that will exist in other subdirectories.
import python ;
if ! [ python.configured ]
{
ECHO "notice: no Python configured in user-config.jam" ;
ECHO "notice: will use default configuration" ;
using python ;
}
use-project boost
: ./boost ;
project
: requirements <library>/boost/python//boost_python ;
# A little "rule" (function) to clean up the syntax of declaring tests
# of these extension modules.
rule run-test ( test-name : sources + )
{
import testing ;
testing.make-test run-pyd : $(sources) : : $(test-name) ;
}
build-project hello_world ;
# build-project [[other projects]]... ;
Then I have a subdirectory containing my 'hello_world' project (name changed to protect the innocent), which contains a Jamfile:
PROJECT_NAME = hello_world ;
import python ;
python-extension interpolation_ext :
$(PROJECT_NAME).cpp
:
<define>FOO
;
# Put the extension and Boost.Python DLL in the current directory, so that running script by hand works.
install convenient_copy
: $(PROJECT_NAME)_ext
: <install-dependencies>on <install-type>SHARED_LIB <install-type>PYTHON_EXTENSION
<location>.
;
# Declare test targets
run-test $(PROJECT_NAME) : $(PROJECT_NAME)_ext test_$(PROJECT_NAME)_ext.py ;
That 'convenient_copy' sure is convenient, but I haven't found much documentation about it, unfortunately.
Anyway, the idea is that while I'm in the "hello_world" project directory, I make code changes and type 'bjam' regularly. This has the effect of building the Python extension and then running the test_hello_world_ext.py file, which does an 'import hello_world_ext' to test that the extension has built correctly, and then a bunch of rather trivial unit-tests. If they all pass, then bjam reports success.
The problem seems to be that sometimes bjam runs the Python test before it has run the 'convenient_copy' rule, which means that it performs the test on the previous version of the extension, and then overwrites it with the new version. This means I'm frequently having to run bjam twice. In fact, the second time bjam knows that something is out-of-date because it actually does something. The third and subsequent time it does nothing until I make further source changes. It's like the classic double-make problem when a dependency isn't correct.
The main problem with this is that it's often failing a successful build (because the existing extension was bad), and other times it is showing a bad build as successful. It actually took me several weeks to notice this behaviour, around the same time I thought I was going insane, perhaps not coincidentally...
It also seems to do this more often on Linux than OS X, but I'm not completely sure. Feels that way though, and I divide my time between both environments fairly equally.
Also, am I the only person who finds bjam's 'jamfile' syntax utterly confusing? There's a lot going on under the hood that I simply don't understand, or can find adequate documentation for. I'd gladly use make or SCons instead but I wasn't able to get those working either due to broken examples here and there. What really confuses me is how bjam builds many, many other targets before getting on to my files, which would make writing a makefile quite tricky I think? As I am quite familiar with GNU Make and SCons, is it worth my time abandoning bjam to use one of those instead?
The order of declaring targets in a jamfile doesn't determine the order of building the targets. Use dependencies to control the build order.
It would be done like this here:
Change the run-test rule to accept requirements argument:
rule run-test ( test-name : sources + : requirements * )
{
import testing ;
testing.make-test run-pyd : $(sources) : $(requirements) : $(test-name) ;
}
Modify $(PROJECT_NAME) target declaration to add a dependency requirement on convenient_copy:
run-test $(PROJECT_NAME) : $(PROJECT_NAME)_ext test_$(PROJECT_NAME)_ext.py : <dependency>convenient_copy ;
Regarding the part on jamfile syntax etc.:
If you do anything with Boost.Build apart from really trivial things, you should definitely read its User Manual. My personal experience is that after reading it from start to the end, I choose Boost.Build over other build systems any day. YMMV

Build and reference my own local package in Go

I'm playing with Google Go and I'm having fun (!), but I'm having some problems with package subsystem.
I'm running Go 1.0.1 on Mac OS X Lion. I've build also various single file programs without problems (I've also build a small webapp using html/templates without problems and it compiles and runs without any error).
I've defined a "reusable" package (even.go):
package even
func Even(i int) bool {
return i % 2 == 0
}
func Odd(i int) bool {
return i % 2 == 1
}
and a consumer program (useeven.go):
package main
import (
"./even"
"fmt"
)
func main() {
a := 5
b := 6
fmt.Printf("%d is even %v?\n", a, even.Even(a))
fmt.Printf("%d is odd %v?\n", b, even.Odd(b))
}
But when I compile the "library" using
go build even.go
I got nothing... No errors, no message... What happens?
How should I do this?
The answer to your question, "How should I do this?" is explained in How to Write Go Code. It's really pretty important stuff and worth taking a look at.
The behavior of go build might seem puzzling, but is actually conventional for command line programs--no output means that the program ran successfully. So what did it do? For that your answer is in go help build
... Otherwise build compiles the packages but discards the results,
serving only as a check that the packages can be built.
What, you wanted more? Of course. "How to Write Go Code" explains good ways of doing this. For a quick fix to your program, I'll explain that the go command expects each package and each executable program to be in a separate directory. If you just make a directory called even, immediately under the location of useeven.go, and move even.go to it, then go run useeven.go should run just as you have it.
go build only generates an output file when it builds a "single main package". If you want to output a file for your other package you should use go install. That will build and install that package to your pkgs directory.
As noted in a comment by the OP, go build and go run useeven.go work fine, once you put even.go in its own folder: ./even/even.go. There is a bit of Go magic in the ./ (in the import) that makes the "local package" build automatically without requiring it to be installed anywhere.
useeven/
├── even
│   └── even.go
└── useeven.go
If you wanted to make this work without the magic ./, then the library need to be installed. A quick-and-dirty way (at the risk of polluting your library namespace) of making this work for your project is to simply register the library's source location by using a symbolic link like so (in this example GOPATH is ~/go):
[ useeven ]
$ ln -s $(pwd)/even ~/go/src
Now when you build the program, it automatically performs a go get even to install an up-to-date version of your library.
Note that this doesn't make go install* work for the library, it just makes doing that unnecessary.
There are more idiomatic ways of doing this, if you're not in a hurry: How to import local packages in go?
The reason that output is not being generated here is because you're running the
go build even.go
command on the package and not the main go file. Doing so on the package will check for errors on the package, but because it's not a main with an output, no success messages will be generated. If there are issues with the package's contents, errors will be displayed, otherwise if it compiles fine there will be no output
Instead, you should run:
go build useeven.go
To create the binary, then to execute the binary and get output from the program:
./useeven

Resources