On 5/17/11 3:28 PM, Faré wrote: […]
Hope this helps.
I'm gonna need a bit more time to chew over the ASDF code, but thanks for the general direction. I must confess that in spite of the reasonable looking documentation and having contributed the function translation code to ASDF, its whole output translation API has never really gelled in my understanding as a totality. Maybe I can contribute some examples to the texinfo file when the fuzz in my understanding resolves a bit.
BTW, for cl-launch and XCVB, I indeed am looking for a way to create bundles from compiled stuff. How do I create a jar from ABCL and a set of lisp files, precompiled or not?
A reasonable packaging mechanism for ABCL plus "compiled stuff" composed of ASDF system definitions that works well in a Java ecosystem is precisely the itch I'm in the process of scratching for ABCL right now. The base unit of packaging in Java is the jar file, which is nothing more than a ZIP archive with (possibly) some Java-the-language specific metadata. Currently, one can package an ASDF definition in a jar file, push the location of the asd file into ASDF:*CENTRAL-REGISTRY* using the [ABCL JAR-PATHNAME conventions][1] for which a subsequent ASDF:LOAD-SYSTEM will do the right thing.
[1]: http://trac.common-lisp.net/armedbear/browser/trunk/abcl/doc/design/pathname...
For instance, if you were to package up cl-ppcre installed via [quicklisp][10^9monkey-wants-this] in a jar file via
unix$ cd ~/quicklisp/dists/quicklisp/software && jar cfv /tmp/cl-ppcre-2.0.3.jar cl-ppcre-2.0.3
[10^9monkey-wants-this]: http://www.quicklisp.org
one could subsequently enable an ASDF controlled load of this system via
CL-USER> (push "jar:file:/tmp/cl-ppcre-2.0.3.jar!/cl-ppcre-2.0.3/" asdf:*central-registry)
When loaded, ASDF will compile the system to the user cache.
Some problems here that I'm working through:
1) You can't immediately load FASL out of the jar. In my current hackish way—i.e. without comprehending your advice yet—one has first ASDF compile the system with output translations disabled, and then
(defmethod asdf:perform ((o asdf:compile-op) (c asdf:cl-source-file))) (setf (asdf::output-translations) '((t t))))
in the target JVM to load the ABCL FASLS from the jar.
2) One has to specify the absolute path on the local filesystem (or potentially via a URI) for the jar, which makes things a bit fragile in the typical Java ecosystem usage which shuffles jars around like win32 DLLs (or, to be fair, Unix dynamic libraries) relying merely on the filename to keep things straight. My current insight into a way around would be to define another PATHNAME extension in ABCL for CLASSPATH entries, i.e. "classpath:cl-ppcre-2.0.3.jar!/cl-ppcre-2.0.3/" would refer to the named jar in the JVM CLASSPATH if it exists.
3) ABCL [has a bug][#149] that currently prevents ASDF systems located in the top-level entry of a JAR from being accessed.
[#149]: http://trac.common-lisp.net/armedbear/ticket/149
4) The extremely nice use of [JSS][jss] and [ABCLD's slight modification][abcld] of ASDF to also refer to jar files to dynamically load into the JVM probably needs to be rewritten, otherwise we run into the situation whereby we have jars (i.e. the packaged Java code) within the ASDF packaged jar which A) needs changes within ABCL to completely work and B) would be rather inefficient in that the naive implementation each request for a new entry in the JAR within a JAR would require a complete "reseek" through the enclosed ZIP file.
[jss]: http://code.google.com/p/lsw2/source/browse/#svn%2Ftrunk%2Fjss [abcld]: http://code.google.com/p/abcl-dynamic-install/source/browse?repo=abcld
5) A fear of mine: if I enable all this, I presume that people would start going around creating 'abcl.jar' files with different inclusions of different ASDF packagings. Without a real smart dynamic introspection system that essentially solves the problems in JVM's classpath we would end up with, at the minimum, a rather hostile situation for the end user. "Put 'abcl.jar' in your classpath." "I did, and it still didn't load Maxima." "Well, what's the checksum of your abcl.jar?" "c48d359a23ee" "Oh, you need 846f78c279cb". Ideally, I would like to come up with a mechanism that would require that 'abcl.jar' come from "official" ABCL packaging, but would somehow be able to introspect the JVM classpath to include ASDF definitions.
Comments solicited.
I'm gonna need a bit more time to chew over the ASDF code, but thanks for the general direction. I must confess that in spite of the reasonable looking documentation and having contributed the function translation code to ASDF, its whole output translation API has never really gelled in my understanding as a totality. Maybe I can contribute some examples to the texinfo file when the fuzz in my understanding resolves a bit.
output-translations is not THAT hard to understand, if you read the source code with my previous comments in mind. Patches to the docs are welcome, too.
A reasonable packaging mechanism for ABCL plus "compiled stuff" composed of ASDF system definitions that works well in a Java ecosystem is precisely the itch I'm in the process of scratching for ABCL right now.
Excellent. I hope you provide an API that isn't so ASDF-specific that it's a pain to use with XCVB -- though XCVB can use ASDF as a backend, and considering the slow ABCL start time, it's probably to be the preferred backend on ABCL.
- You can't immediately load FASL out of the jar.
Is that an ABCL limitation?
In my current hackish way—i.e. without comprehending your advice yet—one has first ASDF compile the system with output translations disabled, and then
(defmethod asdf:perform ((o asdf:compile-op) (c asdf:cl-source-file))) (setf (asdf::output-translations) '((t t))))
in the target JVM to load the ABCL FASLS from the jar.
Why that pain? Doesn't the zip process preserve the timestamps?
- One has to specify the absolute path on the local filesystem (or
potentially via a URI) for the jar, which makes things a bit fragile in the typical Java ecosystem usage which shuffles jars around like win32 DLLs (or, to be fair, Unix dynamic libraries) relying merely on the filename to keep things straight. My current insight into a way around would be to define another PATHNAME extension in ABCL for CLASSPATH entries, i.e. "classpath:cl-ppcre-2.0.3.jar!/cl-ppcre-2.0.3/" would refer to the named jar in the JVM CLASSPATH if it exists.
You want CL systems to be in a variety of jars, rather than just a one jar with everything in it?
- The extremely nice use of [JSS][jss] and [ABCLD's slight
modification][abcld] of ASDF to also refer to jar files to dynamically load into the JVM probably needs to be rewritten, otherwise we run into the situation whereby we have jars (i.e. the packaged Java code) within the ASDF packaged jar which A) needs changes within ABCL to completely work and B) would be rather inefficient in that the naive implementation each request for a new entry in the JAR within a JAR would require a complete "reseek" through the enclosed ZIP file.
I welcome patches to ASDF and/or implementation-specific contributions, just like our asdf-ecl.lisp.
- A fear of mine: if I enable all this, I presume that people would start
going around creating 'abcl.jar' files with different inclusions of different ASDF packagings. Without a real smart dynamic introspection system that essentially solves the problems in JVM's classpath we would end up with, at the minimum, a rather hostile situation for the end user. "Put 'abcl.jar' in your classpath." "I did, and it still didn't load Maxima." "Well, what's the checksum of your abcl.jar?" "c48d359a23ee" "Oh, you need 846f78c279cb". Ideally, I would like to come up with a mechanism that would require that 'abcl.jar' come from "official" ABCL packaging, but would somehow be able to introspect the JVM classpath to include ASDF definitions.
Maybe make it hard for anything but the original to be named abcl.jar?
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org Backwards compatible — If it's not backwards it's not compatible — Greg Newton gregnewton@netscape.net
On 5/17/11 10:01 PM, Faré wrote:
I'm gonna need a bit more time to chew over the ASDF code, but thanks for the general direction. I must confess that in spite of the reasonable looking documentation and having contributed the function translation code to ASDF, its whole output translation API has never really gelled in my understanding as a totality. Maybe I can contribute some examples to the texinfo file when the fuzz in my understanding resolves a bit.
output-translations is not THAT hard to understand, if you read the source code with my previous comments in mind. Patches to the docs are welcome, too.
I agree it shouldn't be that hard. And every time I read the code and docs I go "Uh-huh, now I understand." But somehow, like Perl code, when I come back to it two weeks later, I have to start from the beginning. I guess I'm just putting the proverbial stake in the ether to mark my frustration in case others have the same problem, as a) I'm old enough not to care that much if other people think I'm an idiot and b) maybe it's not just me. In amplifying my concern here, I definitely owe you a diff or two to asdf.texinfo to reward your patient explanations…
[…]
- You can't immediately load FASL out of the jar.
Is that an ABCL limitation?
Certainly not: abcl.jar contains FASLs, after all.
In my current hackish way—i.e. without comprehending your advice yet—one has first ASDF compile the system with output translations disabled, and then
(defmethod asdf:perform ((o asdf:compile-op) (c asdf:cl-source-file))) (setf (asdf::output-translations) '((t t))))
in the target JVM to load the ABCL FASLS from the jar.
Why that pain? Doesn't the zip process preserve the timestamps?
Timestamps should be preserved, but the current output translation code looks for FASLs in the user cache. Well, by that reasoning including both statements should be redundant. I need to look at this again…
[…]
You want CL systems to be in a variety of jars, rather than just a one jar with everything in it?
Yep. I wouldn't mind being able to include multiple systems in a single jar, but I want to keep the core abcl separate from the systems in order to be able to consistently rev the core (and, of course, the systems) via checksums.
- The extremely nice use of [JSS][jss] and [ABCLD's slight
modification][abcld] of ASDF to also refer to jar files to dynamically load into the JVM probably needs to be rewritten, otherwise we run into the situation whereby we have jars (i.e. the packaged Java code) within the ASDF packaged jar which A) needs changes within ABCL to completely work and B) would be rather inefficient in that the naive implementation each request for a new entry in the JAR within a JAR would require a complete "reseek" through the enclosed ZIP file.
I welcome patches to ASDF and/or implementation-specific contributions, just like our asdf-ecl.lisp.
I have my eye on that, and when I have mature patches to ASDF that work with ABCL out of the box, I will submit them for consideration. But currently, one needs a specialized build of ABCL with the jscheme and bsh jars in the classpath in order to use the jar-file extensions so this isn't practical. Given the amount of ABCL's lunch that Clojure has eaten, maybe it's time to make some post-ANSI CL decisions in our implementation wrt. ABCL Java/CL interop.
- A fear of mine: if I enable all this, I presume that people would start
going around creating 'abcl.jar' files with different inclusions of different ASDF packagings. Without a real smart dynamic introspection system that essentially solves the problems in JVM's classpath we would end up with, at the minimum, a rather hostile situation for the end user. "Put 'abcl.jar' in your classpath." "I did, and it still didn't load Maxima." "Well, what's the checksum of your abcl.jar?" "c48d359a23ee" "Oh, you need 846f78c279cb". Ideally, I would like to come up with a mechanism that would require that 'abcl.jar' come from "official" ABCL packaging, but would somehow be able to introspect the JVM classpath to include ASDF definitions.
Maybe make it hard for anything but the original to be named abcl.jar?
Not really possible as far as I can figure things to avoid the ability to name things 'abcl.jar' (or are you being sarcastic?) Solving the dynamic introspection problem seems more tractable, at the corresponding runtime cost of building a cache of the contents jars that the JVM knows about, but memory is getting cheaper by the ns, n'est-ce pas?
On Tue, May 17, 2011 at 9:47 PM, Mark Evenson evenson.not.org@gmail.com wrote:
On 5/17/11 3:28 PM, Faré wrote: […]
Hope this helps.
I'm gonna need a bit more time to chew over the ASDF code, but thanks for the general direction. I must confess that in spite of the reasonable looking documentation and having contributed the function translation code to ASDF, its whole output translation API has never really gelled in my understanding as a totality. Maybe I can contribute some examples to the texinfo file when the fuzz in my understanding resolves a bit.
BTW, for cl-launch and XCVB, I indeed am looking for a way to create bundles from compiled stuff. How do I create a jar from ABCL and a set of lisp files, precompiled or not?
A reasonable packaging mechanism for ABCL plus "compiled stuff" composed of ASDF system definitions that works well in a Java ecosystem is precisely the itch I'm in the process of scratching for ABCL right now. The base unit of packaging in Java is the jar file, which is nothing more than a ZIP archive with (possibly) some Java-the-language specific metadata. Currently, one can package an ASDF definition in a jar file, push the location of the asd file into ASDF:*CENTRAL-REGISTRY* using the [ABCL JAR-PATHNAME conventions][1] for which a subsequent ASDF:LOAD-SYSTEM will do the right thing.
For instance, if you were to package up cl-ppcre installed via [quicklisp][10^9monkey-wants-this] in a jar file via
unix$ cd ~/quicklisp/dists/quicklisp/software && jar cfv /tmp/cl-ppcre-2.0.3.jar cl-ppcre-2.0.3
one could subsequently enable an ASDF controlled load of this system via
CL-USER> (push "jar:file:/tmp/cl-ppcre-2.0.3.jar!/cl-ppcre-2.0.3/" asdf:*central-registry)
When loaded, ASDF will compile the system to the user cache.
Some problems here that I'm working through:
- You can't immediately load FASL out of the jar. In my current hackish
way—i.e. without comprehending your advice yet—one has first ASDF compile the system with output translations disabled, and then
(defmethod asdf:perform ((o asdf:compile-op) (c asdf:cl-source-file))) (setf (asdf::output-translations) '((t t))))
in the target JVM to load the ABCL FASLS from the jar.
- One has to specify the absolute path on the local filesystem (or
potentially via a URI) for the jar, which makes things a bit fragile in the typical Java ecosystem usage which shuffles jars around like win32 DLLs (or, to be fair, Unix dynamic libraries) relying merely on the filename to keep things straight. My current insight into a way around would be to define another PATHNAME extension in ABCL for CLASSPATH entries, i.e. "classpath:cl-ppcre-2.0.3.jar!/cl-ppcre-2.0.3/" would refer to the named jar in the JVM CLASSPATH if it exists.
I think this is wrong. Not everyone here is Java-savvy, so I'm going to explain some things you probably already know:
a. CLASSPATH (the listing of directories and jar files where to look for classes) is not a runtime concept; it's only a variable (environment variable or command line switch) used to init the JVM's default class loader. Once the JVM is started, CLASSPATH doesn't make any more sense. b. At runtime there's a hierarchy of class loaders, that, without going too much in detail, define a sort of limited virtual filesystem. Resources in that filesystem might come from plain files, from contents of jars, from the network, from memory... So, classpath:foo.jar!/bar does not make much sense: the fact that bar comes from foo.jar is no longer important (and possibly not even known anymore) inside the virtual filesystem. This is not just theory, I can cite at least two examples: ABCL's very own functions compiled at runtime and loaded from memory, and anything running on JBoss >= 5, where applications are loaded with a classloader that does not expose jar files in any way. So, I would suggest simply classpath:/foo/bar/baz and leave it to the classloader to go and find /foo/bar/baz. This is precisely how the Spring framework does it, for example[1]. What you lose is the ability to enumerate the contents of the "file system": you can only ask for a resource by name and get back a stream if it exists. But I don't think we currently need the capability to enumerate.
[1] http://static.springsource.org/spring/docs/2.0.1/reference/resources.html#re...
- ABCL [has a bug][#149] that currently prevents ASDF systems located in
the top-level entry of a JAR from being accessed.
- The extremely nice use of [JSS][jss] and [ABCLD's slight
modification][abcld] of ASDF to also refer to jar files to dynamically load into the JVM probably needs to be rewritten, otherwise we run into the situation whereby we have jars (i.e. the packaged Java code) within the ASDF packaged jar which A) needs changes within ABCL to completely work and B) would be rather inefficient in that the naive implementation each request for a new entry in the JAR within a JAR would require a complete "reseek" through the enclosed ZIP file.
Another benefit of going through classloaders is that they (at least the default ones) already cache resources and don't reseek the jar every time. And I wouldn't put Java dependencies as jars inside another jar: either you should distribute them as separate jars, or you should "sum" them to a single fat jar or "uberjar" (the latter is typically generated by the Clojure build tool, Leiningen: https://github.com/technomancy/leiningen/blob/stable/TUTORIAL.md).
- A fear of mine: if I enable all this, I presume that people would start
going around creating 'abcl.jar' files with different inclusions of different ASDF packagings. Without a real smart dynamic introspection system that essentially solves the problems in JVM's classpath we would end up with, at the minimum, a rather hostile situation for the end user. "Put 'abcl.jar' in your classpath." "I did, and it still didn't load Maxima." "Well, what's the checksum of your abcl.jar?" "c48d359a23ee" "Oh, you need 846f78c279cb". Ideally, I would like to come up with a mechanism that would require that 'abcl.jar' come from "official" ABCL packaging, but would somehow be able to introspect the JVM classpath to include ASDF definitions.
Why should everything go into abcl.jar? Applications and libraries should go inside their own jars. It's the same as with, e.g., clisp.exe.
Alessio
On 5/17/11 10:24 PM, Alessio Stalla wrote: […]
a. CLASSPATH (the listing of directories and jar files where to look for classes) is not a runtime concept; it's only a variable (environment variable or command line switch) used to init the JVM's default class loader. Once the JVM is started, CLASSPATH doesn't make any more sense. b. At runtime there's a hierarchy of class loaders, that, without going too much in detail, define a sort of limited virtual filesystem. Resources in that filesystem might come from plain files, from contents of jars, from the network, from memory... So, classpath:foo.jar!/bar does not make much sense: the fact that bar comes from foo.jar is no longer important (and possibly not even known anymore) inside the virtual filesystem. This is not just theory, I can cite at least two examples: ABCL's very own functions compiled at runtime and loaded from memory, and anything running on JBoss>= 5, where applications are loaded with a classloader that does not expose jar files in any way. So, I would suggest simply classpath:/foo/bar/baz and leave it to the classloader to go and find /foo/bar/baz. This is precisely how the Spring framework does it, for example[1]. What you lose is the ability to enumerate the contents of the "file system": you can only ask for a resource by name and get back a stream if it exists. But I don't think we currently need the capability to enumerate.
So, if I understand you, 'classpath:/foo/bar/baz' just means find the entry '/foo/bar/baz' relative to something within the classpath? What happens if there are multiple classpath entries that satisfy this requirement, i.e. foobar.jar and barfoo.jar both contain '/foo/bar/baz'? Doesn't a "first one wins" strategy create ambiguity?
[…]
On Tue, May 17, 2011 at 10:52 PM, Mark Evenson evenson@panix.com wrote:
On 5/17/11 10:24 PM, Alessio Stalla wrote: […]
a. CLASSPATH (the listing of directories and jar files where to look for classes) is not a runtime concept; it's only a variable (environment variable or command line switch) used to init the JVM's default class loader. Once the JVM is started, CLASSPATH doesn't make any more sense. b. At runtime there's a hierarchy of class loaders, that, without going too much in detail, define a sort of limited virtual filesystem. Resources in that filesystem might come from plain files, from contents of jars, from the network, from memory... So, classpath:foo.jar!/bar does not make much sense: the fact that bar comes from foo.jar is no longer important (and possibly not even known anymore) inside the virtual filesystem. This is not just theory, I can cite at least two examples: ABCL's very own functions compiled at runtime and loaded from memory, and anything running on JBoss>= 5, where applications are loaded with a classloader that does not expose jar files in any way. So, I would suggest simply classpath:/foo/bar/baz and leave it to the classloader to go and find /foo/bar/baz. This is precisely how the Spring framework does it, for example[1]. What you lose is the ability to enumerate the contents of the "file system": you can only ask for a resource by name and get back a stream if it exists. But I don't think we currently need the capability to enumerate.
So, if I understand you, 'classpath:/foo/bar/baz' just means find the entry '/foo/bar/baz' relative to something within the classpath?
No, not exactly. "/foo/bar/baz" is an absolute path, so it's not relative to something *within* the classloader search path; but it *is* relative to the actual classloader. I oversimplified; there's not a unique "virtual file system" (VFS) but a tree of them, and the root is the classloader you consider. A classloader is the aggregation of one or more sources (e.g. jars). Within ABCL, typically the classloader is the one that loaded ABCL, i.e. you don't have to worry about it and you can pretend there's a single VFS. It only becomes a problem in a scenario where ABCL is a library shared among several different applications (running on the same JVM): then, you would typically have to use each application's class loader. Relative paths are also possible; for example, you might want to load a FASL that is "next to" another one.
What happens if there are multiple classpath entries that satisfy this requirement, i.e. foobar.jar and barfoo.jar both contain '/foo/bar/baz'? Doesn't a "first one wins" strategy create ambiguity?
Yes, it does. There is a way to detect the ambiguity and get a list of all the resources with a given name [1]; we could decide to forbid that situation and signal an error (when loading Lisp code). For reference, it's not how things typically work in Java: the possibility of ambiguity is accepted, and while it is a source of bugs, it's also voluntarily exploited in certain scenarios to override classes without touching the containing jars. Granted, with a dynamic language, that becomes pretty much irrelevant. That said, my main points are: - you can't expect to always being able to detect which jar a resource comes from (or if it comes from a jar at all) - even if you could determine the jar, you could only check it afterwards, i.e. it's not "find jar, then look for resource" but "find resources, then choose the one from the right jar". Otherwise, the classpath: prefix is misleading. But then, what does "the right jar" mean if you're no longer using absolute paths? Suppose you have classpath:my.jar!/foo. What if the classloader knows both foo from /home/alessio/my.jar and foo from /usr/lib/my.jar? Which one is the right one?
[1] http://download.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html#...
Alessio
armedbear-devel@common-lisp.net