About
In C, libcdio provides a widely-ported
and highly-usable library for retrieving data from CDs (and disc images). This
is an area which Haskell has thus far been lacking a solution for; while modern
technology has admittedly been moving away from discs in favour of downloading
files over the internet, there is still some utility in the medium for any
programmers whose projects might involve external storage (note, however, that
libcdio
only allows /reading/ discs, and leaves /authoring/ to other
libraries).
While the majority of the core library has been translated, many supplemental
headers (MMC commands, CD-Paranoia, etc.) are not yet available; for the
current progress see the FEATURES file and the
ROADMAP for the rough order in which those are planned to be
developed, and please do report any bugs you find (or even fix them yourself!)
License
The original libcdio
is licensed under the GPL, and these bindings, of
course, follow suit. If you do use this in your own project, therefore, you
are subject to the ambiguity of whether linking to a GPL library then requires
your own code to also be released under the GPL. Look elsewhere for a full
discussion on what arguments are given in that debate, but in short, the GPL
says that "a work based on the Program" must also be released under the GPL.
To err on the side of caution, if you use this library, release your code under
the GPL. To do otherwise is to take a firm stance against the linking argument
at best, violate the copyright at worst, and make GPL proponents angry at you
either way.
Installation
Requirements
As with nearly every Haskell project, the .cabal
file maintains the list of
dependencies, and that should be taken as authoritative over anywhere else
except Hackage revisions, and I'll try to keep the code up to date with those.
Notably, the actual core of this package is the C libcdio
library. All
bindings should fail gracefully for any version within the supported range, and
so should be safe to call blindly, but this is accomplished via preprocessor
commands, and so this package must be recompiled whenever the base libcdio
version changes. Minor version bumps to the underlying library (and certainly
patch releases) should still run safely after being recompiled, but there may
be some unexpected behaviour: version 2.1 added a few meta-values to the
Language
enum, for example, at values greater than 255, while the previous
maximum value was below that. It is possible for a C compiler to have used a
byte representation for <2.1 and a larger one for >=2.1; something like that
could possibly result in things being set at/referenced from the wrong memory
offset.
* libcdio: >= 0.93 && < 2.2
* c2hs: >= 0.26
* ghc: >= 8.0
c2hs + ghc
Some parts of the bindings have been written for the c2hs
preprocessor, and
while manual compilation is technically possible, it's much more involved than
necessary. Instead, just use cabal-install
or stack
as usual. If you
really do have to invoke gcc
manually, however, run that preprocessor first:
c2hs --cppopts=-E --cppopts=-Iinclude/ --include=.../ src/Foreign/Libcdio/Types/Enums.chs
c2hs --cppopts=-E --cppopts=-Iinclude/ --include=.../ src/Foreign/Libcdio/Types/Offsets.chs
Usage
The original implementation revolves around a classically-C architecture of
threading a mutable (though opaque) pointer through through many function
calls. For those used to that or who are following pre-existing guides, a
set of low-level bindings mirroring that architecture may be found under
the "Foreign.Libcdio" tree; for anyone used to Haskell, the monadic
bindings under "Sound.Libcdio" are recommended instead. A lookup table for
translating existing code and/or knowledge into each progressively higher-level
interface is provided in the documentation of the Foreign.Libcdio.*
modules.
As a general rule, any project should /only/ import modules from a single set
of bindings, not both, as while the datatypes can frequently be passed between
them, several function names have been reused and so may collide.
Contributing
I welcome any patches, whether for bug fixes, new features, or anything else.
If you just want to point out a bug or ask for some yet-unmentioned feature, I
maintain that list in ISSUES; see the README
in that directory for the format if you want to submit something in a more
complete form or contribute to any ongoing discussion, but otherwise feel free
to simply email me and I'll wrangle it into the
right form.
If you decide to contribute yourself, please enable the dev
build flag.
For the moment, it just enables all warnings I want to enforce in the code, but
it might provide other aids in the future as well. I've avoided enabling them
during everyday building as while an end user seeing a warning might feel
inclined to fix the program, chances are it's just going to be ignored as the
list of built files scrolls by.
cabal configure -fdev
Depending on the size of your hack, I welcome either a diff file, or you can
bundle your complete darcs patches with darcs send
. Either way, attach the
changes to an email addressed to ag@eitilt.life and I'll see about adding it to
the codebase.
If you do send the latter, every patch should have a comment with a (at least
mildly) descriptive name prefixed with a tag indicating the general category
addressed by the patch: for fixing issues, that is an "i/" followed by the
issue number (padded with leading zeros to three digits); for general
development, "f/" followed by the best topic in the FEATURES
key; for
completeness, version tags are "v/" followed by the package reference followed
by the version. All are terminated with a final period.
Please do not squash patches. Each patch should represent a minimal but
complete change: certainly enough context to successfully compile, hopefully
enough context to not break any previously-passing tests, and potentially
combining closely-related changes at your discretion, but if you wind up trying
to decide between multiple tags or you're adding all of your work over the
entire day, you should probably look closely at whether you can break the patch
apart any farther.
Additionally, make good use of the --ask-deps
flag. Until I get a CI
integration together, it's easy to miss a dependency, but do your best to
select anything which your patch may require to build successfully.