У меня есть программная среда, основанная на CMake 3.11.4 и Python 3.7.
В моих библиотеках / программах есть файл config.txt
, описывающий их зависимости в указанном мной формате. Затем у меня есть сценарий Python (scripts/configure.py
), который генерирует CMakeLists.txt
на лету, а затем вызывает CMake для создания решения, которое может быть построено в Visual Studio 2015.
Я хочу Python для автоматического повторного запуска при редактировании config.txt
пользователем.
Поэтому я заставил свой сценарий Python добавить пользовательский оператор команды в сгенерированный CMakeLists.txt
. Вот как это выглядит для проекта с именем «myproject», включающего две библиотеки «lib1» и «lib2».
${SDE_ROOT_DIR}/build/myproject/CMakeLists.txt
содержит:
# Automatically re-run configure project when an input file changes:
set( PROJECT_DEPENDENCIES )
list( APPEND PROJECT_DEPENDENCIES "${SDE_ROOT_DIR}/lib/lib1/config.txt" )
list( APPEND PROJECT_DEPENDENCIES "${SDE_ROOT_DIR}/lib/lib2/config.txt" )
ADD_CUSTOM_COMMAND( OUTPUT ${SDE_ROOT_DIR}/build/myproject/CMakeLists.txt COMMAND tools/python/Python370/python.exe scripts/configure.py myproject WORKING_DIRECTORY ${SDE_ROOT_DIR} DEPENDS ${PROJECT_DEPENDENCIES} )
Вот что я делаю:
- Я запускаю свой сценарий (
scripts/configure.py myproject
), чтобы сгенерировать CMakeLists.txt
и решение Visual Studio. - Затем я открываю решение
- Первый когда я строю, он сообщает
Generating CMakeLists.txt
, и я вижу, что мой сценарий scripts/configure.py
вызывается. Этого не ожидается! - Во второй раз, когда я строю, ничего не происходит. Это нормально.
- Если я редактирую
config.txt
, в следующий раз, когда я строю, я вижу Generating CMakeLists.txt
и вижу, что мой скрипт scripts/configure.py
вызывается. Это хорошо.
Это почти то, что я ожидал, за исключением того факта, что мой скрипт запускается при первой компиляции проекта. Поскольку CMakeLists.txt
был только что сгенерирован и определенно новее, чем config.txt
, я не понимаю, почему он должен генерировать CMakeLists.txt
снова.
Есть идеи, что я могу делать не так? Есть ли какие-либо дополнительные команды, которые я должен добавить к CMakeLists.txt
, чтобы по умолчанию вывод этой пользовательской команды был "актуальным"?
Вот MCVE (config.txt
заменяется на prgname.txt
):
prg/main.cpp
:
#include <iostream>
int main( int argc, char* argv[] )
{
std::cout << "Hello World!" << std::endl;
return 0;
}
prg/prgname.txt
:
myprogram
scripts/configure.py
:
import sys
import subprocess
import argparse
import os
from contextlib import contextmanager
@contextmanager
def pushd(newDir):
previousDir = os.getcwd()
os.chdir(newDir)
yield
os.chdir(previousDir)
def configure_project():
# check configuration args
parser = argparse.ArgumentParser(description="CMakeLists generator.")
parser.add_argument('project', metavar='project', type=str, help='project name')
args = parser.parse_args()
working_directory = os.getcwd()
project = args.project
buildfolder = os.path.normpath(os.path.join( os.path.dirname(os.path.abspath(__file__)), os.pardir, "build", project ))
if not os.path.isdir(buildfolder):
os.makedirs(buildfolder)
prgsourcefolder = os.path.normpath(os.path.join( os.path.dirname(os.path.abspath(__file__)), os.pardir, "prg" ))
prgbuildfolder = os.path.join( buildfolder, "prg" )
if not os.path.isdir(prgbuildfolder):
os.makedirs(prgbuildfolder)
prgnamepath = os.path.join( prgsourcefolder, "prgname.txt" )
with open( prgnamepath, "r" ) as prgnamefile:
prgname = prgnamefile.read()
with open( os.path.join( prgbuildfolder, "CMakeLists.txt" ), "w" ) as cmakelists:
cmakelists.write( "add_executable(" + prgname + " " + os.path.join(prgsourcefolder,"main.cpp").replace("\\","/") + ")\n" )
cmakelistspath = os.path.join( buildfolder, "CMakeLists.txt" )
with open( cmakelistspath, "w" ) as maincmakelists:
maincmakelists.write( "cmake_minimum_required(VERSION 3.11)\n" )
maincmakelists.write( "project(" + project + ")\n" )
maincmakelists.write( "add_subdirectory(prg)\n" )
maincmakelists.write( "add_custom_command( OUTPUT " + cmakelistspath.replace("\\","/") + " COMMAND python " + " ".join( [ x.replace("\\","/") for x in sys.argv] ) + " WORKING_DIRECTORY " + working_directory.replace("\\","/") + " DEPENDS " + prgnamepath.replace("\\","/") + ")\n" )
# Run CMake:
with pushd( buildfolder ):
cmd = ['cmake.exe', '-G', 'Visual Studio 14 2015 Win64', buildfolder]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
out = proc.stdout.read(1)
if proc.poll() != None:
break
sys.stdout.write(out.decode())
sys.stdout.flush()
proc.wait()
if __name__ == "__main__":
import sys
sys.exit( configure_project() )
- Добавьте CMake и Python к вашему
PATH
- Из папки скриптов запустите
python configure.py myproject
- Откройте
build/myproject/myproject.sln
- Нажмите "compile all" и вы Вы увидите неожиданное сообщение
Generating CMakeLists.txt
в журнале