使用python脚本控制cmake的方法和方法脚本的生成

09/15 06:07:52 来源网站:辅助卡盟平台

本文使用 Zhihu On VSCode 创作并发布

在我们使用cmake构建c++项目,仍然会遇到各种各样的问题,比如设置编译器路径,生成配置,install的配置等等。这是仍然需要一些细碎的cmake指令。这时,就可以使用python脚本来执行构建命令。通过python脚本生成一列的cmake的指令,控制cmake生成规则,从而控制程序的生成。下面就讲述python脚本控制cmake的方法。

具体代码,见这里

设置项目路径

给出当前脚本路径变量

scriptDir = os.path.dirname(os.path.realpath(__file__)) # 给出脚本的路径

给出项目路径

# 给出项目的路径,所以,脚本和项目的相对位置要设置好
projRoot = os.path.abspath(os.path.join(scriptDir)) 
# projRoot = os.path.abspath(os.path.join(scriptDir, "..", "..", ".."))

可以利用脚本路径相对于项目根目录的位置设置项目根目录

解析脚本执行时给出的变量

parser = argparse.ArgumentParser() # 解析命令
#positional argument
parser.add_argument('type', help='specify build type as Release or Debug')
#optional argument, solver solver has just 1 component
parser.add_argument('projecName', help='specify the component to build')
args = parser.parse_args()

需要给出两个变量:

根据传入的type类型,确定build的类型

# 确定build的类型,默认为Release
buildType="Release"
if (args.type == "Release") or (args.type == "release"):
    buildType = "Release"
elif (args.type == "Debug") or (args.type == "debug"):
    buildType = "Debug"
elif (args.type == "Coverage") or (args.type == "coverage"):
    buildType = "Coverage"
elif (args.type == "Coverage_Release") or (args.type == "coverage_release"):
    buildType = "Coverage_Release"
else:
    print("Error: ")
    print("  Unrecognized build type " + args.type)
    sys.exit("Aborted!")

使用subprocess.call命令调用脚本输出cmake版本

try:
    
    # 这个方法的作用是执行一些命令行的命令,例如 sh xxx.sh , java -jar xxx.jar 等,(相当于执行shell命令?)
    # 会开启一个子进程去执行,并且等待子进程结束才继续执行其他的,使用起来非常方便,就是需要注意一些小细节
    # subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。
    subprocess.call(['cmake', '--version']) 
except OSError:
    print("")
    print("Error: ")
    print("  Cannot find cmake")
    sys.exit("Aborted!")

根据不同系统执行不同命令

通过if os.name == "posix": # posix指的是linux/MAC来判断系统,然后执行不同的命令

根据创建类型给出目录名称

installSubDir = "linux64" + suffix # 给出install目录
    solverBuildDir = solverBuildDir + suffix # 给出build的目录,根据suffix的不同,会有不同的文件夹
    buildInstallCMD = "make -j4 install" # 给出build的脚本命令
    buildTestCMD = "make tests" # 给出test的命令
    cmakeSLTN = "Unix Makefiles" # cmake使用的generator类型

确定编译器位置,lib库位置等

#compilers
    #compilerPath = "/usr/local"      #给出gcc的目录
    compilerPath = "/usr/gcc/9.3.0"   #gcc 9.3 #给出gcc路径
    cCompiler = compilerPath + "/bin/gcc" # gcc位置
    cxxCompiler = compilerPath + "/bin/g++"# g++位置
    fCompiler = compilerPath + "/bin/gfortran" # gfortran位置
    stdlibPath = compilerPath + "/lib64" # lib位置
    makeCmd = "/usr/local/bin/make" # make的位置
    if not os.path.isfile(makeCmd):# 如果make不在‘makeCmd’中的话
        makeCmd = "/usr/bin/make" # 认为其在此处
    check_file(makeCmd) # 判断其是不是file
    # LIB的路径,为给出的gcc路径‘stdlibPath’和系统的lib路径,将`gcc`lib路径添加到系统`lib`路径中
    os.environ["LD_LIBRARY_PATH"] = stdlibPath + ":" + os.environ["LD_LIBRARY_PATH"]

其他命令和目录等

cmakeSLTN = "\"" + cmakeSLTN + "\"" + archSLTN # 添加双引号
installDir = os.path.join(projRoot, "install") # 添加install目录
buildDir = os.path.join(projRoot, "build") # 添加builds目录
sourceDir = os.path.join(projRoot) # 确定CMakeLists.txt文件目录
ProjectSourceDir = os.path.join(sourceDir)

生成目录

os.makedirs(buildDir) # 创建builds的子目录

检查目录

    # 检查目录,这些目录需要提前创建好
    check_dir(buildDir)
    check_dir(installDir)
    check_dir(sourceDir)
    print("")
    print("----------------------------------------------")  
    print("project root dir: ", projRoot)
    print("build type      : ", buildType)
    print("install dir     : ", installDir)

开始组装最后的cmake命令

actualInstall = os.path.join(installDir, installSubDir)
    configCMD = "cmake -D CMAKE_INSTALL_PREFIX:PATH=" + actualInstall
    if os.name == "posix":
        configCMD = configCMD + " -D CMAKE_BUILD_TYPE:STRING=" + buildType # build类型
        configCMD = configCMD + " -D CMAKE_C_COMPILER:PATH=" + cCompiler # c编译器位置 
        configCMD = configCMD + " -D CMAKE_CXX_COMPILER:PATH=" + cxxCompiler # c++编译器位置

开始执行build过程

将当前目录转到builds下的某个项目目录下:

 # 判断是否存在mfe的目录
    if not (os.path.exists(mfeSourceDir)):
        sys.exit("multife source folder does not exist!")
    if os.path.exists(mfeBuildDir):
        print()
        print("Warning: folder " + mfeBuildDir + " exists, deleting")
        print()
        shutil.rmtree(mfeBuildDir)
    os.makedirs(mfeBuildDir) # 创建builds的子目录
    os.chdir(mfeBuildDir) # os.chdir() !!!方法用于改变当前工作目录到指定的路径。

添加额外的build命令

# 结合cmake的-D指令给出build的额外指令
    mfeCMD = configCMD # 给出build的命令
    
    mfeCMD = mfeCMD + " -G " + cmakeSLTN
    mfeCMD = mfeCMD + " " + ProjectSourceDir # 给出source的目录
    print("------------")
    mfeCMD1="cmake ../ "
    subprocess.call(mfeCMD, shell=True) #启动shell脚本,执行mfeCMD指令,即‘cmake xxx‘指令
    print("------------")
    subprocess.call(buildInstallCMD, shell=True) # 即'make xxx'指令

执行设定好的mfeCMD脚本命令

print("------------")
subprocess.call(mfeCMD, shell=True) #启动shell脚本,执行mfeCMD指令,即‘cmake xxx‘指令
print("------------")
subprocess.call(buildInstallCMD, shell=True) # 即'make xxx'指令

最后形成的cmake指令

上面的所有一切python脚本需要gdb模块python脚本需要gdb模块,最终结果都体现在最后的cmake命令上:

'cmake 
-D CMAKE_INSTALL_PREFIX:PATH=/media/linux/cplus/cmake-tutorial-bilibili/buildScriptExample_blog/install/linux64_dbg  # 生成的install路径
-D CMAKE_BUILD_TYPE:STRING=Debug  #生成项目build类型
-D CMAKE_C_COMPILER:PATH=/usr/bin/gcc #找到的gcc编译器位置
-D CMAKE_CXX_COMPILER:PATH=/usr/bin/g++ #找到的g++编译器位置
-G "Unix Makefiles" /media/cplus/cmake-tutorial-bilibili/buildScriptExample_blog' #generator类型

这样就把命令交给cmake去执行了,完成了python控制编译的任务。

总结使用python脚本生成cmake的指令从而控制cmake的编译最终,我们的设置都会变成cmake的指令去交给cmake执行

    暂无相关资讯
使用python脚本控制cmake的方法和方法脚本的生成