I understand that lein deps :tree displays a dependency tree of all the project dependencies (implicit and explicit). However, "each dependency is only shown once within a tree." I'd really like to see a tree where this wasn't the case, and that if libraries A and B require library X, library X shows up under both A and B.
Does anyone know how to do this with lein or some other tool?
You can generate Maven's POM out of Leiningen's project definition and then use Maven's dependency:tree plugin with a verbose option, like this:
$ lein pom
$ mvn dependency:tree -Dverbose=true
This will list dependencies omitted for various reasons, e.g.:
| +- ring:ring-core:jar:1.4.0:compile
| | +- (org.clojure:clojure:jar:1.5.1:compile - omitted for conflict with 1.7.0)
| | +- (org.clojure:tools.reader:jar:0.9.1:compile - omitted for conflict with 0.10.0-alpha3)
| | +- (ring:ring-codec:jar:1.0.0:compile - omitted for duplicate)
For more options to dependency:tree see its documentation.
This can now be done using leiningen by lein deps :tree. Note the space between deps and :tree.
This can be done without Leiningen using tools.deps. With a minimal deps.edn file like:
{:deps {}}
Then view the tree with:
% clj -Stree
org.clojure/clojure 1.10.1
org.clojure/spec.alpha 0.2.176
org.clojure/core.specs.alpha 0.2.44
Related
I'd like to use a few classes from the LLVM project in my own Objective-C app. Specifically, I want to use the classes declared in BitstreamReader.h and BitstreamWriter.h. Unfortunately, I don't have much experience linking C++ libraries, so I don't really know where to begin. I started by installing llvm through Homebrew with brew install llvm#14. Then, in my Xcode project, I tried linking the libraries in /opt/homebrew/opt/llvm#14/lib, and adding /opt/homebrew/opt/llvm#14/include/** to my HEADER_SEARCH_PATHS.
Now I'm completely stuck. I have a bunch of build errors in Xcode like:
"Reference to unresolved using declaration"
"No member named 'ldiv' in the global namespace"
"Use of undeclared identifier 'wcspbrk'"
...
Any help at all would be greatly appreciated. Thanks!
In C++ world there are quite a few ways to incorporate a dependency into your project, I'll outline some of them, but will try to describe in details one which I find the most suitable for your scenario:
1. Installing libraries system/user-wide
This is the most classic approach, when you have the libraries pre-compiler and pre-installed for your specific platform so they are available under default library search-path. It's similar to how system frameworks in iOS are used - you only add linker command to the project, while the frameworks (libraries) exist independently from it (or don't exist, which causes linker error). The problem with this approach, is that you cannot really use the libs for restricted systems, where "default" libraries are unchangeable (iOS, tvOS, iPadOS)
2. Embedding static libraries
Another approach is to precompile all libraries you need into archives for all platforms the libraries are supposed to be used and then just embed one of the library version which is required into your final app binary. This approach is somewhat cumbersome and unportable because it will require you to compile the lib and re-embed it manually each time you need some parts of library changed or new platform supported.
3. Embedding an xcframework
This approach is very similar to the previous one with a few benefits that you can wrap binaries for all platforms under one package and even release it in SPM.
4. Using CMake build system
Many projects (and LLVM is not an exception) in C++ are made with use of so-called CMake tool. It's widely adopted multi-platform build system and one of the benefits you can employ is that you can easily include any other project as part of your own. At the same time CMake is not widespread at all in the world of mobile development, so you may have hard time finding relevant information for these platforms.
5. Using Xcode workspaces
This is the solution I'd like to describe in more details. In a nutshell this approach consists of 6 steps:
Download LLVM project repo;
Generate Xcode project for required LLVM libraries with use of CMake;
Make an Xcode workspace and add the newly generated project to it;
Add your own project to the same workspace;
Add required dependencies from LLVM project to your own;
Adjust project settings to make it compatible with the dependencies.
The benefits of this approach is that it gives the most consistent experience (after generating project, all parts are configurable from Xcode), freedom of managing the source code (the LLVM project files can be altered however you want), and luxury of built-in dependency graph (all libraries required to build a target are given under Xcode settings).
Downloading LLVM project
You can clone the project from here. Be advised that this has to be in the same folder your future workspace will be in, so you better prepare it in advance:
% mkdir MyWorkspace && cd MyWorkspace
% git clone git#github.com:llvm/llvm-project.git
Generating LLVM Xcode Project
First, ensure you have CMake installed (it doesn't come out of the box with macOS). You can use brew or just download the app from the official site. After that create a new folder for the future Xcode project next to llvm-project repo folder and run cmake on the LLVM toolkit project:
% mkdir LLVM && cd LLVM
% cmake -GXCode ../llvm-project/llvm
Creating Xcode workspace
Nothing fancy here, just open Xcode and navigate to File/New/Workspace menu (Ctrl+Cmd+N shortcut). Ensure that your workspace is created in the MyWorkspace folder. You can just do it from Xcode:
Then, add the LLVM project created on the previous step. Open File/Add Files to "MyWorkspace"... menu (Option+Cmd+A) and select the Xcode project file:
If Xcode suggests to auto-create schemes I recommend accepting this suggestion so you don't have to deal with it yourself later on.
Adding your own project
This step mimics the previous one with exception that you add your own project to the workspace. I didn't have an existing project for that, so I just created a new one (in my case macOS command-line app) in the workspace directory. If you do the same, ensure that the project is added to "MyWorkspace" and the folder is correct:
Eventually your workspace "Project Navigator" should look something like this:
And here is how the directory tree looks like in a nutshell:
% tree -L 2
.
|-- LLVM
| |-- $(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
| |-- CMakeCache.txt
| |-- CMakeFiles
| |-- CMakeScripts
| |-- CPackConfig.cmake
| |-- CPackSourceConfig.cmake
| |-- Debug
| |-- LLVM.xcodeproj
| |-- MinSizeRel
| |-- RelWithDebInfo
| |-- Release
| |-- benchmarks
| |-- build
| |-- cmake
| |-- cmake_install.cmake
| |-- docs
| |-- examples
| |-- include
| |-- lib
| |-- llvm.spec
| |-- projects
| |-- runtimes
| |-- test
| |-- third-party
| |-- tools
| |-- unittests
| `-- utils
|-- MyProject
| |-- MyProject
| `-- MyProject.xcodeproj
|-- MyWorkspace.xcworkspace
| |-- contents.xcworkspacedata
| |-- xcshareddata
| `-- xcuserdata
`-- llvm-project
|-- CONTRIBUTING.md
|-- LICENSE.TXT
|-- README.md
|-- SECURITY.md
|-- bolt
|-- clang
|-- clang-tools-extra
|-- cmake
|-- compiler-rt
|-- cross-project-tests
|-- flang
|-- libc
|-- libclc
|-- libcxx
|-- libcxxabi
|-- libunwind
|-- lld
|-- lldb
|-- llvm
|-- llvm-libgcc
|-- mlir
|-- openmp
|-- polly
|-- pstl
|-- runtimes
|-- third-party
`-- utils
Adding dependencies to your project
From this point forward you'll only need Xcode to finish the job. First, let's link the libraries you need to the project and start from the Bitstream archive. Open your project's target General tab settings and under Framework and Libraries click the + sign which should take you to the screen with all local dependencies currently available. It's quite a long list of tools from the LLVM project + native Apple libs, so you may want to filter it as needed to find the required position:
Now the tricky part. You might not actually be required to do that, but if the LLVMBitstreamReader target itself relies on symbols of other libraries (and exposes such a dependency with explicit use of the libraries symbols) the project linking will fail, so to be safe go to the LLVMBitstreamReader build settings and check what it depends on under Target Dependencies section:
Now add these dependencies to your project as well. Eventually your Frameworks and Libraries section should look like this:
Adjusting project settings
CMake generated Xcode projects come with peculiarities. In our case the build folders for the LLVM project targets are located under the project directory with the name matching selected configuration (Debug/Release/MinSizeRel/RelWithDebInfo). In order for your own project's targets to find the libraries built with the given configuration you either have to adjust the LLVM project/targets settings, which I don't recommend because it's a lot of manual work, or just add custom library search path to your project. For the latter go the Build Settings of the target where you added the dependencies at the previous step, find Library Search Path item and add $(SRCROOT)/../LLVM/$(CONFIGURATION)/lib as a new item:
Another tricky part is that dependent targets won't make dependencies to build if the dependencies' targets have incompatible build settings. Incompatible is a vague term here, but commonly it means matching the Architectures section. Luckily in our case it merely means making Release configuration to build active architecture only (the Debug shouldn't require any changes at all):
Last, but not least, the headers of the library. After generating the LLVM Xcode project, the headers it offers don't (completely) come with the project and are actually located in the repository folder. You may just copy the headers right into your own project, but I suggest adding the repo directory in the System Headers Search paths to stay consistent with the LLVM Xcode Project settings (you can yourself check where the headers search paths are under the the LLVMBitstreamReader Build Settings). Similarly to lib search path, I suggest use help of settings variables and add this path flexibly:
$(SRCROOT)/../llvm-project/llvm/include
$(SRCROOT)/../LLVM/include
Finale
At this point you should be good to use the LLVMBitstreamReader library and classes defined there. I renamed my main.m to main.mm so clang knows i'm going to use C++ in my code, and here is my sample code:
//
// main.mm
// MyProject
//
// Created by Aleksandr Medvedev on 14.12.2022.
//
#import <Foundation/Foundation.h>
#import <llvm/Bitstream/BitstreamReader.h>
#import <iostream>
int main(int argc, const char * argv[]) {
llvm::BitstreamBlockInfo::BlockInfo info;
info.Name = "Hello, LLVM!";
std::cout << info.Name << std::endl;
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
}
return 0;
}
If everything is done right, it should compile without any errors now.
P.S. I many times focused on specific directory hierarchy for a reason - when an XCode project is generated through CMake it often uses absolute paths, not relative and if you move your project to another directory, you will have to either adjust the paths in the build settings of required targets/projects or repeat the step with generating the LLVM Xcode project again.
so I'm using NB with the C++ plugin and Git version control so I can work with colleagues.
I don't know what files are supposed to be "tracked" and we are getting problems because if we only add the code files to git, new files are not being automatically add to NB but only in the physical folder. We figured out that the configuration file is the problem but if we had it to repository we get another problem, absolute paths to the files.
What is the solution for this?
Cheers
I don't know what files are supposed to be "tracked"
As a rule of thumb:
Source / test files
NetBeans project files nbproject (some files only, see below!)
Possible project related files, that are not generated for each compilation
Makefile
What shouldn't go into git (and therefore onto your gitignore):
build directory
dist directory
within nbproject ignore these:
private dir
The Package-* and Makefile-* files
About the last (Package-* / Makefile-*) files i'm not completely sure - please try with them on gitignore first.
Let's assume such a project - put everything with a (x) on gitignore:
<project>
|
+- build/ (x)
|
+- dist/ (x)
|
+- nbproject/
| |
| +- private (x)
| |
| +- some files (as above)
|
+- src/
|
+- test/
|
+- Makefile
I am currently working on a project, that looks like this:
root folder
|---plugin manager
| |---plugin_manager.cpp
| |---plugin_interface.hpp
|
|---libraries
|
|---Plugins
| |
| |---Plugin1
| | |---Plugin1.cpp
| | |---Plugin1.hpp
| |---Plugin2
| | |---Plugin2.cpp
| | |---Plugin2.hpp
I am compiling a .so for each plug-in and then I "load" it with the plugin_manager. This works fine. I even created a simple makefile, which is able to compile a .so. Here are my make and config files:
configure.ac
AC_INIT(My Project, 0.1, my#email, myproject)
AC_PREREQ(2.68)
AC_COPYRIGHT(GNU General Public License)
AM_CONFIG_HEADER([config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_PROG_LIBTOOL
AC_PROG_INSTALL
AC_PROG_CXX
AM_INIT_AUTOMAKE([1.9 foreign])
AC_CONFIG_FILES(Makefile)
AC_ENABLE_SHARED
AC_DISABLE_STATIC
LT_INIT
AC_OUTPUT
Makefile.am
ACLOCAL_AMFLAGS = -I m4
#Generating libtest.so
lib_LTLIBRARIES = libtest.la
#here you can list your source files
libtest_la_SOURCES = Plugin1.cpp
libtest_la_LDFLAGS = -module -avoid-version -export-dynamic
However, this make file is not that user-friendly, since I have to put it manually in each plug-in folder and also change its source files. That is why I want to create another one, which basically by typing make creates an executable in the plugin manager folder, as well as a .so in each plug-in folder. I have been reading for the last couple of days about autotools and tried implementing something similar to what the guys here suggested, but it didn't work. So I hope that there is someone here, who has experience with such makefiles and can give me a tip on how to solve my problem.
Automake has limitations even with wildcards (http://www.gnu.org/software/automake/manual/html_node/Wildcards.html).
I do not thing that to do what you want is possible without using a bash script to generate your Makefile.am.
However, if using CMake is not a problem for you.
You should be able to do it with something like
FILE(GLOB dir_list "${CMAKE_CURRENT_SOURCE_DIR}/Plugins/*")
FOREACH(dir_entry dir_list)
FILE(GLOB file_src "${dir_entry}/*.cpp"
add_library(plugin_${dir_entry} ${file_src})
ENDFOREACH(dir_entry dir_list)
I'm trying to find a way to build a big modular C++ project with CMake.
The structure of the project is the following:
--project_root
--src
--folder_1
--source_1.h
--source_1.cc
--test_source_1.cc // file containing a main with unit tests
--folder_2
--source_2.h
--source_2.cc
--test_source_2.cc // file containing a main with unit tests
--folder_3
...
And so on.
Each folder represent a project module and each module might depend on other modules, so for example source_1.h may include source_2.h.
Every module folder may also contains a test file so the whole project will have multiple executables.
How can I build the whole project with CMake? How should I write my CMakeLists.txt file?
Thank you a lot.
There are many, many examples out there of how to structure CMake projects for C++, many of which are referenced by the tutorial #user2485710 suggested in his comment, so I'm not going to go super in-depth here, but I'll at least give you a good starting point based on the way you want to lay out you folder structure.
The nice thing about CMake is that it can essentially do a tree-decent using the add_subdirectory command. This lets us easily divide up our CMake code to only do what is required at any specific directory level. In otherwords, each CMakeLists.txt file should only do the minimal amount of work needed to properly set up things at the current depth in the directory tree. In you example, your CMake tree might look like this:
--project_root
--src
--CMakeLists.txt
--folder_1
--CMakeLists.txt
--source_1.h
--source_1.cc
--test_source_1.cc // file containing a main with unit tests
--folder_2
--CMakeLists.txt
--source_2.h
--source_2.cc
--test_source_2.cc // file containing a main with unit tests
...
In src/CMakeLists.txt you do all of your project-level initialization, I.E. find_package, setting up your include-path, etc. Then you simply add the following at the end:
add_subdirectory(folder_1)
add_subdirectory(folder_2)
...
This tells CMake that it should look in those folders for additional stuff to do. Now in src/folder_1/CMakeLists.txt, we do the actual work of whatever combination of add_executable and add_library you need to properly build source_1.cc and test_source_1.cc, and likewise in src/folder_2/CMakeLists.txt for source_2.cc, etc.
The other nice thing is that any CMake variables you set higher up the tree are propagated down through add_subdirectory. So, for example, in src/CMakeLists.txt you can check for some sort of 'build unit-test' flag and set the CMake variable there, and then all you have to do in the other CMakeLists.txt files is check for that variable. This can also be super useful to do if you have a project where CMake is dynamically generating header files for you based on checking environment variables for path-names and the like.
If the structure of the project is well-regulated, you could write custom macros or function of cmake to define the modules and their dependencies.
The cmake scripts in OpenCV project is a good reference:
/libs/opencv-2.4.8/sources/
|+cmake/
|+doc/
|~modules/
| |+core/
| | |+doc/
| | |+include/
| | |+perf/
| | |+src/
| | |+test/
| | `-CMakeLists.txt
| |~imgproc/
| | |+doc/
| | |+include/
| | |+perf/
| | |+src/
| | |+test/
| | `-CMakeLists.txt
| |+ml/
| |+...
| |-CMakeLists.txt
|-CMakeLists.txt
root/modules/imgproc/CMakeLists.txt
set(the_description "Image Processing")
ocv_define_module(imgproc opencv_core)
You will need a CMakeLists.txt in each folder where building will occur.
project() is used to set the name of your overall project.
add_subdirectory() is used to command the configuration to process the CMakeLists.txt in that directory.
add_executable() is used to create an executable from included sources.
add_library() is used to create a static or dynamic library that can be added to executables or libraries as a dependency.
Using a build script (.bat, .cmd, or .sh) will allow you to automate some of the cmake process, such as setting up an out-of-source configuration or build.
You should look up the documentation for these commands on the cmake website, https://cmake.org/cmake/help/latest/
When I move some subdirectory away from project managed by "./configure" and all that things, it tries to get to some "../../configure.ac" and other things and is not easily buildable.
How to extract part of such project and make it independent?
There is two ways to deal with this, create a separate auto-tools build process or do away with the auto-tools and hand code or make a new Makefile.
myprojectfoo
|
+-- src
|
+-- man
|
+-- messages
|
+-- lib
|
+-- include
|
+-- others
Have a look at the illustration above, for a fictitious project called myprojectfoo and is using auto-tools to build a binary called foo. The top-level directory i.e. myprojectfoo will have configure.ac, Makefile.am and Makefile.in, in the subdirectories there would be at least Makefile.am and Makefile.in. The auto-tools will create and execute the make commands to build the project.
Now, from what I'm understanding in what you are trying to do:
myprojectfoo
| \ /
+-- sXc
| / \
+-- man
|
+-- messages
|
+-- lib
| \ /
+-- incXude
| / \
+-- others
You want to take out the src subdirectory and it's include's also. Then in that case, it would be easier to create a separate Makefile (read - no auto-tools) build.. in that case, it would be easier.
The best way I can think of it is, you will have to make that decision ultimately, how big is the subset of the project's sources you want to extract, once you go ahead with that, remove all references to Makefile.am, Makefile.in... and borrow an existing simple Makefile template to build it and invoke it like this
make -f MyMakefile
OR
If you want to build a separate project using that subset using auto-tools:
Create a bare-bones Makefile.am as shown below.
Create a bare-bones configure.ac as shown below...
Run autoscan on the source to pick out the dependencies, add the results of the output file 'configure.scan' to the configure.ac
Run automake (Do this once!)
Run autoconf then. It may complain about missing files such as INSTALL, COPYING etc
Then any subsequent changes to configure.ac, run autoreconf after that, which will execute automake, autoconf, and other supporting auto-tools programs.
Taking a sample of the Makefile.am for Linux...
SUBDIRS = src include
ACLOCAL_AMFLAGS = -I m4
Taking a sample of the configure.ac for Linux...
AC_PREREQ(2.63)
AC_INIT([mysubsetprojectfoo], [0.1a], [foo#bar.baz])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([-Wall -Werror])
AM_GNU_GETTEXT_VERSION([0.17])
AM_GNU_GETTEXT([external])
AM_CFLAGS=
# Checks for programs.
AC_HEADER_STDC
AC_PROG_CC
AC_ARG_ENABLE([debug],
[ --enable-debug Turn on debugging],
[case "${enableval}" in
yes) debug=true ;;
no) debug=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;;
esac],[debug=false])
AM_CONDITIONAL([DEBUG], [test x$debug = xtrue])
# Checks for libraries.
AC_CHECK_LIB([mylib], [mylib_function], [:])
if test "$mylib" = :; then
AC_MSG_ERROR([MyLib is missing.\
This can be downloaded from 'http://www.foo.baz'])
fi
AC_CONFIG_HEADERS([config.h])
# Checks for header files.
# FROM running 'autoscan' on the source directory
AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h locale.h netinet/in.h stdlib.h string.h sys/ioctl.h sys/socket.h syslog.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_INLINE
AC_C_CONST
AC_TYPE_SIGNAL
AC_TYPE_PID_T
AC_TYPE_UID_T
AC_TYPE_SIZE_T
# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_CHECK_FUNCS([atexit inet_ntoa memset regcomp socket strdup strerror])
AC_CONFIG_FILES([Makefile src/Makefile include/Makefile])
AC_OUTPUT
The commands for the auto-tools, is top of my head and I may have missed something..feel free to point out by placing a comment on this at the bottom of this post and it will be amended accordingly.