Can Leiningen recursively download the dependencies of its checkout dependencies? - clojure

Checkout dependencies can be used to add another work-in-progress project to your Leiningen project during development (for example: you're developing an app and underlying library in parallel).
However, when a checkout dependency itself has a "traditional" dependency (from Clojars), running lein run in the parent project will throw a java.io.FileNotFoundException since it apparently does not retrieve the "traditional" dependencies of its checkout dependencies.
Is there a way to let a Leiningen project recursively download the dependencies of its checkout dependencies?

My opinion of the "proper" way to do this is to have your project depend on the library in your checkouts directory as a traditional dependency in addition to having it in your checkouts directory.
Then every time you change dependencies, run lein install in your library project. This will cause lein to generate the appropriate jar file and install it into your local maven repo. It does not matter if this library project is finished, because you are not actually running it in this state, just using it to fetch dependencies.
Then when it does work you don't have to do anything to "switch to production" other than remove your checkouts directory. The dependency is already in place in the dependent project.
There is a side effect of using checkouts to work on libraries in that the code is loaded twice. Once from the "depended on" version, and then again from the "checkouts version". This is very occationally a problem for me when I'm using protocols and have to remember to re-load the protocol definition.

Related

Is it possible to consume conan package's binaries outside of conan cache?

Let's say I have two projects. Lib and App.
App has Lib in it's conanfile.txt. Normally when conan install of App's dependencies is performed conan downloads and compiles Lib to ~/.conan/data/.
Is it possible to link App to Lib that is currently being worked on instead (e.g. /home/path/to/code/Lib/cmake-build-release/lib/ )?
The reason I want to do this is to debug a Lib's bug whose only known way to reproduce is by using App. I want to be able to quickly add std::cout to certain places and incrementally recompile. Rebuilding the whole conan package and doing conan install each time is too long. I was thinking about some hack that would change include path and linking path.
Yes, it is possible, Conan uses the same approach as Python pip: the "editable" packages. You can read more about it in this section of the docs: Editable packages. The basic idea is:
You cd libfolder and define it as a package in edition: conan editable add lib/1.0
You can build the lib there, like conan install . + cmake .. or conan build .
You can go to the App folder cd appfolder and do a conan install .. You should see that lib/1.0 is marked as "editable" and not from the Conan cache. You can build App, and it will be linking your dependency to lib from the local libfolder.
Every change that you do to libfolder and build there locally (incremental builds), will be directly available to App without needing to create or export-pkg to the Conan cache.
The editable feature relies on the correct definition in lib/1.0 of the project layout, in its layout() method. There are built-in layouts like cmake_layout(self).
If the different packages lib and app generate compatible projects, like Visual Studio, it is possible to join those projects in the IDE and have a convenient development and debugging experience of both packages together. There is a live demo in this C++ Italian Meetup presentation

Embedding library and it's includes via CMake

I'm creating a very small project that depends on the following library: https://github.com/CopernicaMarketingSoftware/AMQP-CPP
I'm doing what i always do with third-party libraries: i add their git repo as a submodule, and build them along with my code:
option(COOL_LIBRARY_OPTION ON)
add_subdirectory(deps/cool-library)
include_directories(deps/cool-library/include)
target_link_libraries(${PROJECT_NAME} coollib)
This has worked perfectly for libraries like Bullet, GLFW and others. However, this AMQP library does quite an ugly hack. Their include directory is called include, but in their CMake install() command, they rename it to amqpcpp. And their main header, deps/cool-library/amqpcpp.h, is referencing all other headers using that "fake" directory.
What happens is: when CMake tries to compile my sources which depend on deps/cool-library/amqpcpp.h, it fails because it's not finding deps/cool-library/amqpcpp/*.h, only deps/cool-library/include.
Does anyone have any idea how i can fix this without having to bundle the library into my codebase?
This is not how CMake is supposed to work.
CMake usually builds an entire distributive package of a library once and then installs it to some prefix path. It is then accessible for every other build process on the system by saying "find_package()". This command finds the installed distibution, and all the libs, includes etc. automagically. Whatever weird stuff library implementers did, the resulting distros are more or less alike.
So, in this case you do a lot of unnecessary work by adding includes manually. As you see it can also be unreliable.
What you can do is:
to still have all the dependencies source distributions in submodules (usually people don't bother doing this though)
build and install each dependency package into another (.gitignored) folder within the project or outside by using their own CMakeLists.txt. Let's say with a custom build step in your CMakeLists.txt
use "find_package()" in your CMakeLists.txt when build your application
Two small addition to Drop's answer: If the library set up their install routines correctly, you can use find_package directly on the library's binary tree, skipping the install step. This is mostly useful when you make changes to both the library and the dependent project, as you don't have to run the INSTALL target everytime to make library changes available downstream.
Also, check out the ExternalProject module of CMake which is very convenient for having external dependencies being built automatically as part of your project. The general idea is that you still pull in the library's source as a submodule, but instead of using add_subdirectory to pull the source into your project, you use ExternalProject_Add to build it on its own and then just link against it from your project.

How can I add a local library into my Leinigen project?

I'd like to add a local library of utilities that I wrote to my project in Leinigen without having to make jars of the library, or without copying the code.
Is that possible?
You can use the checkouts feature of leiningen to add a symbolic link to the project directory containing the library.
cd project-dir # where the project.clj file is
mkdir checkouts
ln -s ~/library/project/dir/ checkouts/library-name
Then add a dependency to the project.clj file
EDIT: If your included code is not it's own project then perhaps including the source directly with git submodules is an option, though some would recommend making it a project that can have a version. It's also worth considering running lein install to build jars and put them in your local maven repo since it only takes two words.
ps: i'm assuming your library is a clojure project.

Updating a local dependency in Clojure

My current project is split up in multiple sub-projects using lein-sub. The core sub-project depends on other sub-projects. Right now, I'm typically working through the repl and simply re-compiling the current namespace to get an updated result; However, whenever I update a sub-project, and try to re-compile that namespace, I don't get the updated results for those projects. I've tried to delete everything in target/ and re-installing the dependencies, but nothing is working.
How would I be able to reload sub-projects in the quickest way possible?
lein-sub doesn't put your subprojects on the classpath; if they're available at all, I expect that's due to a lein sub install issued at some point?
For the type of simultaneous interactive development you're asking about you can use Leiningen's built-in checkouts feature. Just create a directory called checkouts in the root of your top-level project and in there create symbolic links to the root directories of the dependencies. You still need to add them as :dependencies to project.clj, but the fresh code from the checkouts will be used. You can then run your REPL in the top-level project while simultaneously working on all of them, reloading the individual namespaces from the dependencies just like you would with those from the top-level project.
See the tutorial (link to the version on master) for a detailed description.

Using Maven 1.x without extra plugins, how does someone build an executable jar?

Using Maven 1.x with just the bundled/standard plugins, what configuration is necessary to build an executable Jar?
Answers should cover:
including dependencies in target Jar
proper classpath configuration to make dependency Jars accessible
Well the easiest way is to simply set the maven.jar.mainclass property to the main class you'd like to use.
As far as setting up the manifest classpath you can use maven.jar.manifest.classpath.add=true to have maven automatically update the classpath based on the dependencies described in the project.xml.
Disclaimer: It's been a long time since I've used Maven 1 and I did not test any of this out, but I'm pretty sure this will get you started in the right direction. For more information check out the jar plugin docs.