CMake build with LLVM Project as a subdirectory - cmake

TLDR
I want to build the LLVM project monorepo as a subdirectory to a larger CMake project. But the usual paradigm of add_subdirectory(llvm-project/llvm) doesn't give the desired results. How can I add LLVM to my CMake project so that building the project also builds LLVM?
Background
I have project tree that looks like this (some files and subdirectories omitted for brevity) :
.
├── build/
├── CMakeLists.txt
├── cunit/
│ ├── CUnit/
│ │ └── CMakeLists.txt
│   └── CMakeLists.txt
├── hayai/
│   └── CMakeLists.txt
├── install/
├── llvm-project/
│   ├── clang/
│   ├── clang-tools-extra/
│   ├── compiler-rt/
│   ├── debuginfo-tests/
│   ├── libcxx/
│   ├── libcxxabi/
│   ├── libunwind/
│   ├── lld/
│   ├── lldb/
│   ├── llvm/
│ │ └── CMakeLists.txt
│   ├── openmp/
│   └── polly/
└── mylib/
   └── CMakeLists.txt
As you can see, I have four subdirectories, all of which are CMake projects in their own right, and all of which build individually with no problems. Both CUnit and Hayai are unmodified. Mylib is the product of my research, and uses CUnit and Hayai as git submodules/dependencies. I have also modified the LLVM Project monorepo to use Mylib for instrumentation as part of my research, but it builds on its own. I would like to unify all four of these subprojects as one CMake-driven build.
The content of the top-level CMakeLists.txt is:
cmake_minimum_required(VERSION 3.2)
project (myproject)
set(CMAKE_BUILD_TYPE Debug)
add_subdirectory(cunit/CUnit)
add_subdirectory(hayai)
add_subdirectory(mylib)
add_subdirectory(llvm-project/llvm)
Problem
When I try to generate the build using the following command:
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=../install -DCMAKE_BUILD_TYPE=Debug -DBUILD_HAYAI_SAMPLES=false -DBUILD_HAYAI_TESTS=false
I get an error from CMake once it recurses into the LLVM subproject (shortened for brevity):
-- LLVM host triple: x86_64-unknown-linux-gnu
-- LLVM default target triple: x86_64-unknown-linux-gnu
-- Building with -fPIC
-- Constructing LLVMBuild project information
-- Linker detection: GNU ld
CMake Error: File ./llvm-project/llvm/include/llvm/module.modulemap.build does not exist.
CMake Error at ./llvm-project/llvm/include/llvm/CMakeLists.txt:7 (configure_file):
configure_file Problem configuring file
-- Targeting AArch64
-- Targeting AMDGPU
-- Targeting ARM
-- Targeting BPF
-- Targeting Hexagon
-- Targeting Lanai
-- Targeting Mips
-- Targeting MSP430
-- Targeting NVPTX
-- Targeting PowerPC
-- Targeting Sparc
-- Targeting SystemZ
-- Targeting X86
-- Targeting XCore
-- Configuring incomplete, errors occurred!
See also "./build/CMakeFiles/CMakeOutput.log".
See also "./build/CMakeFiles/CMakeError.log".
llvm-project/llvm/include/llvm/CMakeLists.txt contains:
add_subdirectory(IR)
add_subdirectory(Support)
# If we're doing an out-of-tree build, copy a module map for generated
# header files into the build area.
if (NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
configure_file(module.modulemap.build module.modulemap COPYONLY)
endif (NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
I checked the two files at the end of the output, but neither had messages relevant to the problem.
Questions
What does the error from CMake really mean? Why doesn't module.modulemap.build exist, or more accurately, why does it exist when building just LLVM?
How can I fix this so that my top level project can build all four subprojects?
Potentially Related
This StackOverflow question asks a similar question using a lot of the same keywords, but has a different task in mind: she/he wants to link to libraries from an existing LLVM build, not build LLVM itself.
Likewise this StackOverflow question and the accepted answer's reference to this LLVM documentation page is about embedding LLVM libraries out of tree into a standalone project. It's not quite what I want since I need to build my entire modified LLVM compiler toolchain.
This llvm-dev mailing list thread sounds like exactly what I'm doing, but the suggested answer doesn't work, as stated above.

What does the error from CMake really mean?
#Tsyvarev correctly identified that the problem was in fact that llvm-project/llvm/include/llvm/module.modulemap.build didn't exist. This was because I downloaded an archive of the project through Github, which appears to have excluded .build files by default. When cloning or forking the project, the missing files are present.
The problem is reproducible, but I don't know why Github behaves the way it does. That is beyond the scope of the question.
How can I fix this so that my top level project can build all four subprojects?
Using add_subdirectory(llvm-project/llvm) command in the top-level CMakeLists.txt file is sufficient, but you must also specify LLVM's options at generate time, of course.

Related

Compile and link library at once in CMake

I'm new in CMake enviroment. I have this project-structure tree:
/my_proj
│
├── deps
│   └── my_dep
│   └── CMakeLists.txt
├── src
│ └── main.cpp
└── CMakeLists.txt
Where my_dep is a git submodule used as dependency for my_proj project.
Usually I compile separatly these two entities, compiling first the library my_dep and then linking it to my_proj exe.
cd my_proj/deps/my_dep
cmake . && make
...compiling library...
cd my_proj
cmake . && make
...compiling exe and linking the above lib...
Now I would like be able to compile both library than executable in once, with a single CMake command.
The /my_proj/CMakeList.txt file must contaign all needed commands to first compile the my_dep lib and generate the .a/.so file, and after this compile the my_proj exe and finaly link the lib with exe.
I want make this procedure in once, with only a make command, e.g.
cd my_proj
cmake . && make
...compile lib, compile exe and link lib to exe...
Can you give me a simple explanantion about make it possible?

Simple way to add a Premake subproject inside a CMake project?

I use CMake for my C++ projects and I like to have my dependencies as Git submodules inside a third-party folder so I can have easy access to the code and the possible CMake targets I can link with.
.
├── CMakeLists.txt
├── src
│   └── main.cpp
└── third-party
└── CMakeSubmodule # OK
└── CMakeLists.txt # OK
My root CMakeLists.txt would typically contain :
add_subdirectory(src)
add_subdirectory(third-party/CMakeSubmodule)
target_link_libraries(myTarget PRIVATE SubmoduleTarget)
Now, I want to add a submodule that only uses premake :
.
├── CMakeLists.txt
├── src
│   └── main.cpp
└── third-party
└── PremakeSubmodule # !
└── premake5.lua # !
How would you do to simply add the submodule as a dependency ?
Do I have to manually convert all premake files to CMakeLists.txt ?
A convenient solution would allow to directly link to a target as follow, so I don't have to manually set the correct include directories and link to the lib files :
target_link_libraries(myTarget PRIVATE PremakeTarget) # Would be great

Is there any way to link add_custom_command to a target defined in another directory with add_custom_target?

Because this is the standard structure of a ROS workspace (robotics framework) I have the following two directories:
ros/
|── DIR_A
│   ├── CMakeLists.txt
│   ├── package.xml
│   ├── README.md
│   ├── setup.py
│   └── src
│   ├── some_code.cpp
|── DIR_B
│   ├── CMakeLists.txt
│   ├── package.xml
│   ├── README.md
│   ├── setup.py
│   └── src
│   ├── some_other_code.cpp
I am trying to add a custom target called clean_compiled that will run the make clean target of a specific external project (already works). But I also need to add a custom command to this clean target in the CMakeLists of another directory. This is what I have:
First CMakeLists.txt:
# We add the custom target
add_custom_target(clean_compiled
COMMENT "Cleaning compilation files in ${SOME_DESTDIR}"
COMMAND $(MAKE) clean PATH=${SOME_DESTDIR}
WORKING_DIRECTORY ${SOME_WORKING_DIRECTORY}
)
Second CMakeLists.txt:
# We try to add a custom command to this custom target
add_custom_command(TARGET clean_compiled
COMMENT "Cleaning compilation files in ${ANOTHER_DESTDIR}"
WORKING_DIRECTORY ${ANOTHER_WORKING_DIRECTORY}
COMMAND $(MAKE) clean PATH=${ANOTHER_DESTDIR}
)
When I run make clean_compiled for the whole repository, I get this warning:
TARGET 'clean_compiled' was not created in this directory.
This warning is for project developers. Use -Wno-dev to suppress it.
And the custom_command is never called.
Is there any way to link the custom command to the target in the other directory without causing circular dependencies?
add_custom_command is pretty clear that it only works with targets in the same directory. There is no way around this. So the second rule cannot be a custom command and needs to be a custom target, for example called clean_another_dest_dir.
https://discourse.cmake.org/t/create-target-that-only-runs-other-target/885/6
You can use add_dependencyto make custom targets depend on other custom targets and make them run, add_dependencies(clean_another_dest_dir clean_compiled), but that isn't always what you want.
Another option is a custom target that runs all the other custom targets.
add_custom_target(clean_all_dir
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR } --target clean_compiled
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR } --target clean_another_dest_dir
)

CTest add tests in subdirectories

I have a CMake-based project that consists of several sub-components, which can all be independently compiled and tested. The directory layout looks like this:
.
├── CMakeLists.txt
├── comp1
│   ├── CMakeLists.txt
│   ├── src
│   │   ├── foo.cc
│   │   └── foo.h
│   └── tests
│   ├── CMakeLists.txt
│   └── test_comp1.cc
└── comp2
├── CMakeLists.txt
├── src
│   ├── bar.cc
│   └── bar.h
└── tests
├── CMakeLists.txt
└── test_comp2.cc
I want to enable ctest, therefore in the root CMakeLists.txt I have include(CTest) and in the component-specific CMakeLists.txt files I have
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
In compX/tests/CMakeLists.txt I have the code to compile the test and the add_test()command. The tests get successfully compiled and I can manually run them. However, if I call ctest, it returns
No tests were found!!!
After playing a bit with this, it turned out that if I move the add_subdirectory(tests) call to the root CMakeLists.txt like this:
if(BUILD_TESTING)
add_subdirectory(comp1/tests)
endif()
it works. But I find this quite ugly and messy, to put component-specific stuff into the root file.
Conversely, I tried to move the include(CTest) command one level down into the component-specific CMakeLists.txt. But ctest complains with this:
*********************************
No test configuration file found!
*********************************
Is there seriously no way to use ctest with a directory structure like above?
The CTest documentation isn't the clearest.
A project I'm working on has a similar directory structure composed of various units, and in each unit are src and tests subdirectories.
CMake documentation says to call "enable_testing()" at the top-level CMakeLists.txt file, and it further says this command will "enable CTest at the current directory and below." Which sounds recursive, right? Well it's not.
Every CMakeLists.txt must have enable_testing() called to enable automatic CTest discovery in that directory.
Thus, in your project, the toplevel CMakeLists.txt will need enable_testing(), then comp{1,2}/CMakeLists.txt will need it, and finally comp{1,2}/tests/CMakeLists.txt will need it.
Once you add those commands and rerun cmake, those directories will each contain a CTestTestfile.cmake file, which is what the ctest program will look for when it runs.

How do I setup a Minecraft Forge development environment?

I want to start creating awesome Minecraft mods, and it seems that the current way to do so is with Minecraft Forge. I already got Gradle and the JDK installed, but no matter what I do I can't seem to get anything to build.
How can I get a Forge development environment working?
After downloading the Forge Mod Development Kit (MDK) archive, it should contain the following files:
forge-somewhere/
├── build.gradle
├── CREDITS-fml.txt
├── eclipse
├── forge-1.10.2-12.18.1.2073-changelog.txt
├── gradle
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── LICENSE-new.txt
├── MinecraftForge-Credits.txt
├── Paulscode IBXM Library License.txt
├── Paulscode SoundSystem CodecIBXM License.txt
├── README.txt
└── src
└── main
├── java
│   └── com
│   └── example
│   └── examplemod
│   └── ExampleMod.java
└── resources
└── mcmod.info
In the README.txt there are instructions on how to set it up, but to put it simple, open a console/terminal in forge-somewhere and run gradle setupDecompWorkspace. It should set up a development environment and then you should be able to run gradle build normally. Note that you have to re-run setupDecompWorkspace for every mod you want to develop/compile.
If you're not using an IDE, or the command fails because of heap memory, you can use gradle setupDevWorkspace instead. This doesn't decompile Minecraft, so you won't be able to check the sources (which you can't without an IDE or something anyway), but it doesn't use nearly as much RAM, which is useful if you're on a lower-end system.
Simple:
Once you have downloaded the Forge .zip for the version that you plan on using, go to the same directory as your "gradlew.bat" file, hold shift-rightclick and open the command prompt.
Type:
gradlew.bat setupDecompWorkspace eclipse
Or if you're running with Intellij Idea (Which I recommend):
gradlew.bat setupDecompWorkspace idea
After that, it'll set up the Workspace as well as the correct coding software package that you wish to be using.