ASDF 或其他独立于家庭和站点配置的模块系统
我正在尝试找出实际应用程序开发的最佳实践。 我无法理解如何正确配置第三方库以将其部署为独立包。 似乎 ASDF-INSTALL 和 ASDF 旨在将库安装到主目录或站点,从而更改开发平台的状态。 如果我正在开发服务器端应用程序并且我想管理盒子上整个 CL 安装的这些依赖项,那就没问题了。
但是,如果我想创建一个独立的应用程序,通过安装脚本部署并在其自己的 CL 实例中单独运行,该怎么办? 我希望避免更改任何其他应用程序的 CL 实例或目标系统配置(即覆盖其他应用程序所依赖的库的其他副本)。 在 Java 中,我所要做的就是创建一个包含这些库的包含目录并设置我的 CLASSPATH。 假设我不安装自己的 CL 运行时,而是使用系统上的内容,如何在 CL 中获得相同级别的隔离?
我发现这是所有动态编译/解释语言的常见问题,因为运行时的生命周期比运行时运行的任何特定应用程序(即 Ruby 或 Python)长,并且应用程序将共享相同的库加载状态。 我没有任何使用此类语言的经验,因此最佳实践可能就是面对面。
我不知道这是否是特定于实现的,但我正在运行 Clozure CL。
编辑:
Ramarren:
我会看看 Mudballs。 谢谢。
安装库与我想要的相反,因为安装意味着修改主机系统状态。 我认为关键一定在你的最后一段。 如何创建启动脚本以将central-registry设置为独立目录? 是否可以使用 ASDF-INSTALL 将内容提取到所述目录中? 如果 CL 实现的基本映像不包含 ASDF(Clozure 默认情况下有 ASDF,但 CLISP 如何做到这一点),如何引导整个过程?
我也在考虑开发团队。 在我创建一个新的 CL 项目存根并对 CVS 或 SVN 进行初始提交后,其他开发人员如何将其检出到本地环境并使用它? 即使假设每个人的配置文件/站点启动中都有 ASDF,其他开发人员的中央注册表中也可能有一组不同的库。 我们不应该仅仅为了一起完成一个项目而同步。 必须有一种干净的方法来从 Emacs/SLIME 启动 CL 运行时的项目特定实例,并准确加载项目中指定的内容,不多也不少。
如果在线有任何 CL 或任何其他语言的最佳实践资源,我将很高兴推出我自己的解决方案并将其开源。
Luis:
SAVE-APPLICATION 适合部署,但不适用于我概述的多开发项目存根。
编辑2:
vatine:
版本依赖性正是这个问题的原因。 如果我正在开发 Perl 或 Ruby Web 应用程序,那么我可以依靠 Webadmin 来管理这些依赖项。 为零售或中小型企业开发应用程序,在这些企业中,Lisp 是一种陌生的技术(我无法说服他们“提高”IT 组织的管理能力),这种方法是不可接受的。
昨晚我能够通过创建一个项目级 .lisp 文件来加载其自己的特定于项目的 ASDF 实例、设置项目本地中央注册表并手动下载来获得我想要的东西依赖库(没有 ASDF-INSTALL,这对于 CLSQL 和 Weblocks 来说是一个痛苦的依赖级联)。 从开发工具的角度来看,它仍然不理想,因为我必须从我的主页和网站中删除 SLIME 和 Clozure 本身的所有自定义。 此外,共享依赖关系也未解决(CLSQL 和 Weblocks 都使用 MD5)。
Java具有类加载器隔离,这就是它解决版本依赖问题的方法。 然后还有一个单独的问题,即如何将所需的库添加到项目中(la Maven)。 前者是核心语言问题; 后者与工具有关。 我将编写一个 SLIME 扩展,它可以执行 ASDF-INSTALL 对项目包含目录(la Maven)所做的操作,并修改 lib 源代码以拦截 defpackage 调用,以某种方式在前面添加 gensym 字符串以强制隔离。 我知道,这种方法有很多漏洞,而且我对包规范了解不够,不知道我能把它埋多深。
我对 Python 一无所知,但我确实知道零售级应用程序的存在; 我一直使用 MusicBrainz Picard。 我将研究一下 Python 是如何做到的。
I'm trying to find out the best practices for real-world application development. I'm having trouble understanding how to properly configure third-party libraries for deployment as a standalone package. It seems that ASDF-INSTALL and ASDF are intended to install libraries to either home or site, changing the state of the development platform. That's fine if I were developing a server side application and I wanted to administer these dependencies for the entire CL installation on the box.
But what if I wanted to create a standalone application, deployed via install scripts, and running alone in its own CL instance? I would want to avoid changing the CL instance or target system configuration for any other applications (i.e. overwrite other copies of libraries that other applications depend on). In Java, all I have to do is create an include directory that contains those libraries and set my CLASSPATH. How do I get the same level of isolation in CL, assuming that I don't install my own CL runtime, and instead use what's on the system?
It occurs to me that this is a common issue with all dynamically compiled/interpreted languages, since the runtime will have a lifetime longer than any particular application that the runtime runs (i.e. Ruby or Python), and applications will share the same library load state. I don't have any experiences with such languages, so the best practice is probably staring me in the face.
IDK if this would be implementation specific, but I am running Clozure CL.
EDIT:
Ramarren:
I'll check out Mudballs. Thank you.
Installing libraries is the opposite of what I want, since installing implies modifying the host system state. I think the key must be in your last paragraph. How do you create the startup script to set central-registry to an isolated directory? Is it possible to use ASDF-INSTALL to fetch stuff into said directory? And how do you bootstrap the whole thing if the base image of your CL implementation doesn't include ASDF (Clozure has ASDF by default, but how would CLISP do it)?
I'm thinking in terms of a dev team too. After I create a new CL project stub and do that initial commit to CVS or SVN, how do other devs check it out to their local environment and work with it? Even assuming that everyone has ASDF in their profile/site startup, other devs may have a different set of libs in their central-registry. We shouldn't have to sync up just to work on a project together. There's got to be a clean way to launch an project specific instance of the CL runtime from Emacs/SLIME and load exactly what's specified in the project, no more, no less.
If there's any best practice resources online, in CL or any other language, I'll be glad to roll my own solution and open source it.
Luis:
SAVE-APPLICATION is good for deployment, but not for the multiple-dev project stub I outlined.
EDIT 2:
vatine:
Version dependency is precisely why this is a problem. If I were developing a Perl or Ruby web app, then I can depend on the existence of a webadmin to manage these dependencies. Developing apps for retail or for small-to-mid-size businesses where Lisp is alien technology (and I cannot convince them to "skill up" their IT org to admin it), that approach is unacceptable.
I was able last night to kind of get what I want by creating a project-level .lisp file that loads its own project-specific ASDF instance, set a project-local central-registry, and manually downloading dependent libs (without ASDF-INSTALL, which was a painful cascade of dependencies for just CLSQL and Weblocks). It still isn't ideal from a dev tools standpoint, since I had to remove all customization from my home and site for both SLIME and Clozure itself. Also, shared dependencies aren't resolved either (CLSQL and Weblocks both use MD5).
Java has class loader isolation, which is how it solves the version dependency issue. Then there's the separate issue of how to get the libs you want into the project (a la Maven). The former is a core language issue; the latter has to do with tools. I'm going to hack together a SLIME extension that does what ASDF-INSTALL does to a project include directory (a la Maven), and modifies lib source code to intercept defpackage calls to somehow prepend a gensym string to enforce isolation. There's plenty of holes in this approach, I know, and I don't know enough about the package spec to know how deep I can bury this.
I don't know anything about Python, but I do know that retail-level apps exist; I use MusicBrainz Picard all the time. I'll look into how Python does it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
对于您的开发环境,您始终可以在某处签入外部库,并让每个开发人员将其签入
asdf:*central-registry*
。另一种选择是拥有一个开发盒,并让每个开发人员在那里运行 Lisp + Swank。
For your development environment, you can always check in the external libraries somewhere, and have each developer check that out into the
asdf:*central-registry*
.Another option is to have a single dev box, and have each developer run a Lisp + Swank there.
我以前也遇到过这样的问题。 我通常解决这个问题的方法如下:
asdf:*central-registry*
以指向工作副本中包含的目录。 asd 文件。
实际上,因为我同时处理多个项目,所以我通常会使用如上所述的多个配置来填充我的 cl init 文件。 例如,
然后,当我启动我的开发环境时,我只需键入
(project1)
,ASDF 就会配置好,供我在项目 1 上下文中工作。一种变体是为每个项目创建一个加载文件,并将其签入源库的根目录中。 该加载文件将配置 ASDF 的中央注册表并加载系统。 通过使用
*load-truename*
,中央注册表的配置可以独立于工作副本的放置。另一种变体是自动搜索工作目录树以查找包含
.asd
文件的所有目录,并相应地填充asdf:*central-registry*
。I have had a problem like this before. The way I have typically solved it is as follows:
asdf:*central-registry*
appropriately in your cl init file to point to the directories in your working copy which contain.asd
files.Actually, because I work on multiple projects concurrently, I typically populate my cl init file with multiple configurations like the above. E.g.,
Then, when I start my development environment, I can simply type
(project1)
, and ASDF will be configured ready for me to work in the project 1 context.A variant is to make a load file for each project, and check it into the root of the source library. This load file will configure ASDF's central registry and load the system. The configuration of the central registry can be independent of the placement of the working copy through use of
*load-truename*
.Another variant is to automatically search the working directory tree to find all the directories that contain
.asd
files, and populate yourasdf:*central-registry*
accordingly.您需要 CCL:SAVE-APPLICATION。
You want CCL:SAVE-APPLICATION.
首先,ASDF 与安装库无关。 它只是一个按照文件之间的依赖关系定义的顺序编译和加载一组文件的工具。 ASDF-INSTALL 安装东西,它使用 ASDF 来确定依赖项(我认为),但还有其他安装机制,例如 clbuild,手动提取和符号链接,或最近开发的Mudballs,它将 ASDF 替换为出色地。
特殊变量
asdf:*central-registry*
保存在 asdf 系统中搜索的目录列表。 它通常包含一个目录的补丁,该目录具有指向实际系统定义文件的符号链接,但这不是必需的,因为它可以只包含带有系统定义文件的每个目录。大多数情况下,此变量将由具有系统/站点库注册表的启动脚本填充,但您可以将其更改为您喜欢的任何内容,包括独立的本地目录。 关于上一段之前的内容,请注意,在同一个 CL 运行时上运行许多应用程序并不特别常见。 通常会启动一些默认的裸核心,然后加载并运行库和应用程序,然后在完成后关闭。
编辑:
ASDF 只是一个库,它的变量就像任何其他 Lisp 变量一样。 在您描述的情况下,您可能想要抑制系统/用户启动脚本,该脚本是特定于实现的(在 CCL 中显然是 -n 或 --no-init 命令行参数),然后手动加载 asdf.lisp,
(setf asdf:*central-registry* (list #p"pathtoprojectcentralregistry"))
。 或者可能创建一个函数来递归扫描项目目录并将所有带有 .asd 文件的子目录推送到那里。First, ASDF has nothing to do with installing libraries. It is simply a tool to compile and load a set of files in an order defined by dependencies between them. ASDF-INSTALL installs things, and it uses ASDF to determine dependencies (I think), but there are other mechanism for installing, like clbuild, extracting and symlinking by hand, or recent development Mudballs, which replaces ASDF as well.
Special variable
asdf:*central-registry*
holds a list of directories which are searched for asdf systems. It usually contains a patch to a directory with symlinks to actual system definition files, but this is not necessary, as it can just contain every directory with a system definition file.This variable will be most of the time populated by startup scripts with system/site library registry, but you can change it to whatever you like, including isolated local directory. Regarding the one before last paragraph, note that it is not particularly common to run many applications on the same CL runtime. Normally some default bare core is launched and then libraries and application is loaded and run, and then shut down when it finishes.
EDIT:
ASDF is just a library and its variables are like any other lisp variable. In the case you describe you likely want to suppress the system/user startup script, which is implementation specific (in CCL it apparently is -n or --no-init command line argument), an then manually load asdf.lisp,
(setf asdf:*central-registry* (list #p"pathtoprojectcentralregistry"))
. Or possibly create a function to recursively scan project directory and push all subdirectories with .asd files there.一般来说,我想说,作为第 3 方库安装的任何内容都应该修改主机系统状态(事实上)。 本地开发的东西可以通过多种方法处理,我使用的是自己的符号链接场(带有附带的 shell 脚本,可以在需要时重建该场)。 Lisp 项目被检出到它们自己的目录中。 相互依赖的项目同样以这种方式进行检查,在其 ASDF 系统定义中相互引用,并通过符号链接场获取。
我在这个模型中看到的一个可能的问题是,如果你突然发现你的部分支持库依赖于 BLAHONGA 库,在 2008 年 12 月 1 日之前从 CVS 中签出,并且你的支持库的其他部分也依赖于 BLAHONGA,但需要一个该功能仅在 2008 年 12 月 29 日起在 CVS 中可用。 我想版本依赖性也可能是一种可能性。
In general, I'd say that anything installed as a 3rd-party library SHOULD modify the host system state (as it were). Stuff developed locally can be handled by several methods, what I use is a symlink farm for myself (with an attendant shellscript to rebuild the farm when I need to). Lisp projects are checked out into their own directories. Inter-dependent projects are likewise checked out that way, reference each other in their ASDF system definitions and are picked up via the symlink farm.
The one possibel problem I see with this model is if you suddenly find that part of your support libraries depend on library BLAHONGA, checked out of CVS before 2008-12-01 and other parts of your support libraries also depend on BLAHONGA, but require a feature only available in CVS from 2008-12-29. I guess version dependencies may be a possibility too.