2015-02-17 13 views
18

Wykonuję niskopoziomowe IO (dla powiązań biblioteki) w Haskell i doświadczam awarii. Chciałbym użyć GHCi na break, aby dowiedzieć się, co się dzieje, ale oto co się dzieje:Debugowanie IO w module pakietu wewnątrz GHCi

> import SDL 
> :break SDL.setPaletteColors 
cannot set breakpoint on setPaletteColors: module SDL.Video.Renderer is not interpreted 

Ponieważ kod naruszającym przepisy nie znajduje się wewnątrz własnych modułów, lecz wewnątrz modułu w opakowaniu zewnętrznym, jest załadowany jako skompilowany kod i najwyraźniej nie mogę użyć : break na skompilowanych modułach.

GHCi manual to potwierdza i zapewnia podpowiedź:

Jest jeden główne ograniczenie: wartości graniczne i single-stepping są dostępne tylko w interpretowanych modułów; skompilowany kod jest niewidoczny dla debuggera [5].

[5] Należy pamiętać, że pakiety zawierają tylko skompilowany kod, więc debugowanie pakietu wymaga bezpośredniego znalezienia jego źródła i ładowania.

Spróbujmy go bezpośrednio:

> :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. 

mogę dodać do mojego zależności .cabal pliku, ale to już czuje się źle. Raz zrobiłem, że:

> :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. 

mogłem zrobić te moduły publicznego, ale w tym momencie wydaje się bardzo niewygodne sposób, aby robić rzeczy, a ja nie (prawdopodobnie poprzez modyfikację .cabal pakietów?) kontynuuj to dalej.

EDIT:

I rzeczywiście próbował to i dostał zaskakujący wynik:

> :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 (bez wykształcenia) przypuszczenie: to dlatego, że moduł zewnętrzny jest nadal związany z mojego kodu jako binarny, i ładowanie go dynamicznie w trybie interpretacji tego nie zmienia.


Tak więc, aby podsumować pytanie: co jest dobrym sposobem na debugowanie IO w opakowaniu zewnętrznym?

Dodatkowe uwagi:

  1. mam źródła do pakietu potrzebne do debugowania; w rzeczywistości, że został dodany do projektu z Cabal piaskownicy dodać source

  2. Alternatywnym rozwiązaniem do korzystania GHCi byłoby dodać ślady do źródła pakietu, ale jest to opcja niefortunne, ponieważ wiąże rekompilacji pakiet dla każdej modyfikacji (ilekroć potrzebuję więcej informacji na temat wykonania i modyfikować ślady), a to zajmuje naprawdę dużo czasu. Interaktywne debugowanie za pomocą GHCi wydaje się lepszym narzędziem do tej pracy, gdybym tylko wiedział, jak go używać.

+0

Dostałeś się dalej niż ja. Nie wiem nawet, jak korzystać z funkcji debugowania GHCi, gdy * są * dostępne - powinienem naprawdę kiedyś RTFM. Jedna sugestia dla Ciebie: chociaż błędy segfaultów mogą wynikać z niewłaściwego używania 'unsafeCoerce' lub' unsafePerformIO', wydaje się, że częstsze jest uzyskiwanie ich ze złych, niebezpiecznych referencji tablica/wektor. Czy niebezpieczna operacja, której używasz, ma bezpieczne odpowiedniki, takie jak 'write', w przeciwieństwie do' unsafeWrite'? Jeśli tak, używanie bezpiecznych wersji do testowania, a następnie przełączanie się na niebezpieczne dla wydajności może sprawić, że rzeczy * znacznie * łatwiej się z nimi uporać. – dfeuer

+1

@dfeuer: W tym przypadku, jak odkryłem dzisiaj, segfault faktycznie pochodził z dereferencji wskaźnika ("Ptr a"), którego pamięć bazowa została już uwolniona przez bibliotekę C (libSDL2), której pakiet używał. To była moja własna wina. Ale wciąż pozostaje pytanie, ponieważ musiałem uciekać się do Debug.Trace, i to w bardziej złożonym przypadku, który może trwać naprawdę długo. –

+0

Żeby się upewnić - czy skonfigurowałeś z 'cabal configure --ghc-option = -fPIC' lub podobnym? Sdl2 README wspomina o tym. – schellsan

Odpowiedz

0

Stos ma pewne wsparcie dla tego.Uruchomienie stack ghci --load-local-deps $TARGET spowoduje załadowanie projektu i wszelkich zależności w polu packages z stack.yaml, w tym jeśli są one oznaczone jako extra-dep s. Przerwy będą wtedy działać. Można debugować zależność w GHCi, uruchamiając stack unpack $PACKAGE i dodając ją do packages w stack.yaml.

To jednak nie jest panaceum. Jeśli pakiety zawierają sprzeczne globalne rozszerzenia językowe (lub inne dynamiczne flagi) lub nazwy modułów, nie będą działać. Na przykład, jeśli Twój pakiet najwyższego poziomu ma default-extensions: NoImplicitPrelude, a twoje zależności nie, nie będą miały zaimportowanego preludium i prawie na pewno nie zostaną załadowane. Zobacz this GHC bug.