'How to collect source files with CMake without globbing?
The CMake documentation explicitly states that file(GLOB ...) is not
recommended to collect source files for a build, but it doesn't
mention what the recommended method actually is.
Specifying every source file manually sounds a little bit too manually
to me. So, what is the right method to collect source files, if not
file(GLOB ...)?
Solution 1:[1]
I use GLOB for exactly that and every time I add a file I run
touch ../src/CMakeLists.txt
The next make command will re-scan the directories.
"There is no way for CMake to generate a build system that knows when a new source file has been added" Really? Okay, so tell it!
It's not 100% automatic but a damn sight easier than adding files manually.
Solution 2:[2]
I use cog, a python module. Here is a sample to collect .cpp file:
The CMakeLists.txt:
set(SRC_FILES "")
# [[[cog
# import cog, glob
# for src in glob.glob('*.cpp'):
# if "skeleton" in src: continue
# cog.outl("SET(SRC_FILES ${SRC_FILES} %s)" % src)
# ]]]
# [[[end]]]
add_library(mylib STATIC ${SRC_FILES})
And then, run:
python -m cogapp -r CMakeLists.txt
The CMakeLists.txt file will be updated in place.
For how to install cog and other usage, please read the article from the author.
Solution 3:[3]
I use a conventional CMakeLists.txt and a python script to update it. I run the python script manually after adding files.
import os
import re
def relFiles(base, sub):
fullSub = os.path.join(base,sub)
abs = [os.path.join(dp, f) for dp, dn, fn in os.walk(fullSub) for f in fn]
return [os.path.relpath(f, base) for f in abs]
def updateAddLibrary(cmakelistsDir, subs):
cmakelists = os.path.join(cmakelistsDir, "CMakeLists.txt")
listings = [relFiles(cmakelistsDir, sub) for sub in subs]
files = [f for listing in listings for f in listing] #flatten
with open(cmakelists, 'r') as file:
text = file.read()
sources = "".join([" %s\n" % f.replace('\\', '/') for f in files])
text = re.sub(r"add_library\s*\(\s*([^\s\)]+).*?\)",
r"add_library(\1\n%s)" % sources,
text, 1, re.DOTALL)
with open(cmakelists, "w") as file:
file.write(text)
dir = os.path.dirname(os.path.abspath(__file__))
updateAddLibrary(dir, ['inc','src'])
Example before:
...
add_library(MyLib
inc/a.h
)
...
after:
...
add_library(MyLib
inc/a.h
inc/sub/b.h
src/a.cpp
)
...
Solution 4:[4]
Following douyw's answer, thank you for your answer.
Not a Cmake expert, don't want to be one, I spent a fxxking 3 hours trying to deal with GLOB(disabled) and aux_source_directory(Not even close to GLOB), and douyw save my life.
I add the recursive file walking, and it's working in my project:
Firstly, install the cogapp python module (python -m pip install cogapp)
set(SRC_FILES "")
# [[[cog
# import cog, os
# for root, _, files in os.walk(".", topdown=False):
# for f in files:
# if not "_unittest" in f: continue
# if not f.endswith(".cpp"): continue
# cog.outl('SET(SRC_FILES ${SRC_FILES} "%s")' % os.path.join(root, f).replace('\\', '/'))
# ]]]
# [[[end]]]
run: python -m cogapp -r CMakeLists.txt
- The upper lines add all "*_unittest.cpp" to the list
- You can change the middle lines to make your own rule, just plain python. Using regex is better, but simple string searching can do the job on the above situation.
- Notice the last line, it needs to replace // to change to the usable universal separator. You may generate your CMakeList.txt in windows.
- You may replace SRC_FILES with whatever you want.
- The python command may be run under Jenkins/TeamCity, triggered by svn/git commit. Then we can automatically add new files.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | spraff |
| Solution 2 | douyw |
| Solution 3 | |
| Solution 4 | Alen Wesker |
