diff options
Diffstat (limited to 'gr-utils/modtool/core')
-rw-r--r-- | gr-utils/modtool/core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-utils/modtool/core/__init__.py | 1 | ||||
-rw-r--r-- | gr-utils/modtool/core/add.py | 132 | ||||
-rw-r--r-- | gr-utils/modtool/core/base.py | 30 | ||||
-rw-r--r-- | gr-utils/modtool/core/bind.py | 65 | ||||
-rw-r--r-- | gr-utils/modtool/core/disable.py | 40 | ||||
-rw-r--r-- | gr-utils/modtool/core/rename.py | 42 | ||||
-rw-r--r-- | gr-utils/modtool/core/rm.py | 50 |
8 files changed, 233 insertions, 128 deletions
diff --git a/gr-utils/modtool/core/CMakeLists.txt b/gr-utils/modtool/core/CMakeLists.txt index 764e79d09c..90f0f3a380 100644 --- a/gr-utils/modtool/core/CMakeLists.txt +++ b/gr-utils/modtool/core/CMakeLists.txt @@ -11,6 +11,7 @@ GR_PYTHON_INSTALL(FILES __init__.py add.py base.py + bind.py disable.py info.py makeyaml.py diff --git a/gr-utils/modtool/core/__init__.py b/gr-utils/modtool/core/__init__.py index 5f89eee30f..cfd60c2f56 100644 --- a/gr-utils/modtool/core/__init__.py +++ b/gr-utils/modtool/core/__init__.py @@ -13,6 +13,7 @@ from __future__ import unicode_literals from .base import ModTool, ModToolException, get_block_candidates from .add import ModToolAdd +from .bind import ModToolGenBindings from .disable import ModToolDisable from .info import ModToolInfo from .makeyaml import ModToolMakeYAML, yaml_generator diff --git a/gr-utils/modtool/core/add.py b/gr-utils/modtool/core/add.py index 852fbe4050..40bfe74d3f 100644 --- a/gr-utils/modtool/core/add.py +++ b/gr-utils/modtool/core/add.py @@ -1,5 +1,5 @@ # -# Copyright 2013-2014,2017-2019 Free Software Foundation, Inc. +# Copyright 2013-2014,2017-2020 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -16,9 +16,11 @@ import os import re import logging -from ..tools import render_template, append_re_line_sequence, CMakeFileEditor +from ..tools import render_template, append_re_line_sequence, CMakeFileEditor, CPPFileEditor, code_generator from ..templates import Templates from .base import ModTool, ModToolException +from gnuradio.bindtool import BindingGenerator +from gnuradio import gr logger = logging.getLogger(__name__) @@ -122,20 +124,20 @@ class ModToolAdd(ModTool): self.validate() self.assign() - has_swig = ( + has_pybind = ( self.info['lang'] == 'cpp' - and not self.skip_subdirs['swig'] + and not self.skip_subdirs['python'] ) has_grc = False if self.info['lang'] == 'cpp': self._run_lib() - has_grc = has_swig + has_grc = has_pybind else: # Python self._run_python() if self.info['blocktype'] != 'noblock': has_grc = True - if has_swig: - self._run_swig() + if has_pybind: + self._run_pybind() if self.add_py_qa: self._run_python_qa() if has_grc and not self.skip_subdirs['grc']: @@ -225,34 +227,98 @@ class ModToolAdd(ModTool): ed.write() self.scm.mark_files_updated((self._file['cminclude'], self._file['cmlib'])) - def _run_swig(self): - """ Do everything that needs doing in the subdir 'swig'. - - Edit main *.i file + def _run_pybind(self): + """ Do everything that needs doing in the python bindings subdir. + - add blockname_python.cc + - add reference and call to bind_blockname() + - include them into CMakeLists.txt """ - if self._get_mainswigfile() is None: - logger.warning('Warning: No main swig file found.') - return - logger.info(f'Editing {self._file["swig"]}...') - mod_block_sep = '/' - if self.info['version'] == '36': - mod_block_sep = '_' - swig_block_magic_str = render_template('swig_block_magic', **self.info) - with open(self._file['swig'], 'a') as f: - f.write(swig_block_magic_str) - is_component = {True: 'gnuradio/' + self.info['modname'], False: self.info['modname']}[self.info['is_component']] - blockname_ = self.info['blockname'] - include_str = f'#include "{is_component}{mod_block_sep}{blockname_}.h"' - with open(self._file['swig'], 'r') as f: - oldfile = f.read() - if re.search('#include', oldfile): - append_re_line_sequence(self._file['swig'], '^#include.*\n', include_str) - else: # I.e., if the swig file is empty - regexp = re.compile(r'^%\{\n', re.MULTILINE) - oldfile = regexp.sub('%%{\n%s\n' % include_str, oldfile, count=1) - with open(self._file['swig'], 'w') as f: - f.write(oldfile) - self.scm.mark_files_updated((self._file['swig'],)) + # Generate bindings cc file + fname_cc = self.info['blockname'] + '_python.cc' + fname_pydoc_h = os.path.join('docstrings',self.info['blockname'] + '_pydoc_template.h') + + # Update python_bindings.cc + ed = CPPFileEditor(self._file['ccpybind']) + ed.append_value('// BINDING_FUNCTION_PROTOTYPES(', '// ) END BINDING_FUNCTION_PROTOTYPES', + 'void bind_' + self.info['blockname'] + '(py::module& m);') + ed.append_value('// BINDING_FUNCTION_CALLS(', '// ) END BINDING_FUNCTION_CALLS', + 'bind_' + self.info['blockname'] + '(m);') + ed.write() + + self.scm.mark_files_updated((self._file['ccpybind'])) + + bg = BindingGenerator(prefix=gr.prefix(), namespace=['gr',self.info['modname']], prefix_include_root=self.info['modname']) + block_base = "" + if self.info['blocktype'] in ('source', 'sink', 'sync', 'decimator', + 'interpolator', 'general', 'hier', 'tagged_stream'): + block_base = code_generator.GRTYPELIST[self.info['blocktype']] + + import hashlib + header_file = self.info['blockname'] + '.h' + hasher = hashlib.md5() + with open(os.path.join(self.info['includedir'], header_file), 'rb') as file_in: + buf = file_in.read() + hasher.update(buf) + md5hash = hasher.hexdigest() + + header_info = { + "module_name": self.info['modname'], + "filename": header_file, + "md5hash": md5hash, + "namespace": { + "name": "::".join(['gr', self.info['modname']]), + "enums": [], + "variables": [], + "classes": [ + { + "name": self.info['blockname'], + "member_functions": [ + { + "name": "make", + "return_type": "::".join(("gr",self.info['modname'],self.info['blockname'],"sptr")), + "has_static": "1", + "arguments": [] + } + ], + "bases": [ + "::", + "gr", + block_base + ], + "constructors": [ + { + "name": self.info['blockname'], + "arguments": [] + } + ] + } + ], + "free_functions": [], + "namespaces": [] + } + } + # def gen_pybind_cc(self, header_info, base_name): + pydoc_txt = bg.gen_pydoc_h(header_info,self.info['blockname']) + path_to_file = os.path.join('python','bindings', fname_pydoc_h) + logger.info("Adding file '{}'...".format(path_to_file)) + with open(path_to_file, 'w') as f: + f.write(pydoc_txt) + self.scm.add_files((path_to_file,)) + + cc_txt = bg.gen_pybind_cc(header_info,self.info['blockname']) + path_to_file = os.path.join('python','bindings', fname_cc) + logger.info("Adding file '{}'...".format(path_to_file)) + with open(path_to_file, 'w') as f: + f.write(cc_txt) + self.scm.add_files((path_to_file,)) + + if not self.skip_cmakefiles: + ed = CMakeFileEditor(self._file['cmpybind']) + cmake_list_var = 'APPEND {}_python_files'.format(self.info['modname']) + ed.append_value('list', fname_cc, to_ignore_start=cmake_list_var, to_ignore_end='python_bindings.cc') + ed.write() + self.scm.mark_files_updated((self._file['cmpybind'])) def _run_python_qa(self): """ Do everything that needs doing in the subdir 'python' to add diff --git a/gr-utils/modtool/core/base.py b/gr-utils/modtool/core/base.py index c867dbd6e9..fee5e20c74 100644 --- a/gr-utils/modtool/core/base.py +++ b/gr-utils/modtool/core/base.py @@ -54,7 +54,7 @@ class ModTool(object): def __init__(self, blockname=None, module_name=None, **kwargs): # List subdirs where stuff happens - self._subdirs = ['lib', 'include', 'python', 'swig', 'grc'] + self._subdirs = ['lib', 'include', 'python', 'grc'] self.has_subdirs = {} self.skip_subdirs = {} self.info = {} @@ -68,7 +68,7 @@ class ModTool(object): self.dir = kwargs.get('directory', '.') self.skip_subdirs['lib'] = kwargs.get('skip_lib', False) self.skip_subdirs['python'] = kwargs.get('skip_python', False) - self.skip_subdirs['swig'] = kwargs.get('skip_swig', False) + self.skip_subdirs['pybind'] = kwargs.get('skip_pybind', False) self.skip_subdirs['grc'] = kwargs.get('skip_grc', False) self._scm = kwargs.get('scm_mode', gr.prefs().get_string('modtool', 'scm_mode', 'no')) @@ -88,8 +88,8 @@ class ModTool(object): """ Validates the arguments """ if not isinstance(self.skip_subdirs['lib'], bool): raise ModToolException('Expected a boolean value for skip_lib') - if not isinstance(self.skip_subdirs['swig'], bool): - raise ModToolException('Expected a boolean value for skip_swig') + if not isinstance(self.skip_subdirs['pybind'], bool): + raise ModToolException('Expected a boolean value for skip_pybind') if not isinstance(self.skip_subdirs['python'], bool): raise ModToolException('Expected a boolean value for skip_python') if not isinstance(self.skip_subdirs['grc'], bool): @@ -114,8 +114,8 @@ class ModTool(object): self.skip_subdirs['lib'] = True if not self.has_subdirs['python']: self.skip_subdirs['python'] = True - if self._get_mainswigfile() is None or not self.has_subdirs['swig']: - self.skip_subdirs['swig'] = True + # if not self.has_subdirs['pybind']: + # self.skip_subdirs['pybind'] = True if not self.has_subdirs['grc']: self.skip_subdirs['grc'] = True @@ -124,8 +124,6 @@ class ModTool(object): def _setup_files(self): """ Initialise the self._file[] dictionary """ - if not self.skip_subdirs['swig']: - self._file['swig'] = os.path.join('swig', self._get_mainswigfile()) self.info['pydir'] = 'python' if os.path.isdir(os.path.join('python', self.info['modname'])): self.info['pydir'] = os.path.join('python', self.info['modname']) @@ -134,6 +132,8 @@ class ModTool(object): self._file['cmlib'] = os.path.join('lib', 'CMakeLists.txt') self._file['cmgrc'] = os.path.join('grc', 'CMakeLists.txt') self._file['cmpython'] = os.path.join(self.info['pydir'], 'CMakeLists.txt') + self._file['cmpybind'] = os.path.join(self.info['pydir'], 'bindings', 'CMakeLists.txt') + self._file['ccpybind'] = os.path.join(self.info['pydir'], 'bindings', 'python_bindings.cc') if self.info['is_component']: self.info['includedir'] = os.path.join('include', 'gnuradio', self.info['modname']) elif self.info['version'] in ('37', '38'): @@ -141,7 +141,6 @@ class ModTool(object): else: self.info['includedir'] = 'include' self._file['cminclude'] = os.path.join(self.info['includedir'], 'CMakeLists.txt') - self._file['cmswig'] = os.path.join('swig', 'CMakeLists.txt') self._file['cmfind'] = os.path.join('cmake', 'Modules', 'howtoConfig.cmake') @@ -158,7 +157,7 @@ class ModTool(object): def _check_directory(self, directory): """ Guesses if dir is a valid GNU Radio module directory by looking for - CMakeLists.txt and at least one of the subdirs lib/, python/ and swig/. + CMakeLists.txt and at least one of the subdirs lib/, and python/ Changes the directory, if valid. """ has_makefile = False try: @@ -186,17 +185,6 @@ class ModTool(object): self.skip_subdirs[f] = True return bool(has_makefile and (list(self.has_subdirs.values()))) - def _get_mainswigfile(self): - """ Find out which name the main SWIG file has. In particular, is it - a MODNAME.i or a MODNAME_swig.i? Returns None if none is found. """ - modname = self.info['modname'] - swig_files = (modname + '.i', - modname + '_swig.i') - for fname in swig_files: - if os.path.isfile(os.path.join(self.dir, 'swig', fname)): - return fname - return None - def run(self): """ Override this. """ raise NotImplementedError('Module implementation missing') diff --git a/gr-utils/modtool/core/bind.py b/gr-utils/modtool/core/bind.py new file mode 100644 index 0000000000..b95178759c --- /dev/null +++ b/gr-utils/modtool/core/bind.py @@ -0,0 +1,65 @@ +# +# Copyright 2013, 2018, 2019 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# +""" Module to call bindtool and create Python bindings """ + + +from __future__ import print_function +from __future__ import absolute_import +from __future__ import unicode_literals + +import os +import logging +import warnings +import subprocess + +try: + from gnuradio.bindtool import BindingGenerator +except ImportError: + have_bindtool = False +else: + have_bindtool = True + +from ..tools import ParserCCBlock, CMakeFileEditor, ask_yes_no +from .base import ModTool, ModToolException + +from gnuradio import gr + +logger = logging.getLogger(__name__) + +class ModToolGenBindings(ModTool): + """ Make YAML file for GRC block bindings """ + name = 'bind' + description = 'Generate Python bindings for GR block' + + def __init__(self, blockname=None, **kwargs): + ModTool.__init__(self, blockname, **kwargs) + self.info['pattern'] = blockname + + def validate(self): + """ Validates the arguments """ + ModTool._validate(self) + if not self.info['pattern'] or self.info['pattern'].isspace(): + raise ModToolException("Incorrect blockname (Regex)!") + + def run(self): + """ Go, go, go! """ + # This portion will be covered by the CLI + if not self.cli: + self.validate() + if not have_bindtool: + logger.error( + "Bindtool required to generate bindings ... Aborting") + return + + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + file_to_process = os.path.join(self.dir, self.info['includedir'], self.info['blockname'] + '.h') + bg = BindingGenerator(prefix=gr.prefix(), namespace=[ + 'gr', self.info['modname']], prefix_include_root=self.info['modname'], output_dir=os.path.join(self.dir, 'python')) + bg.gen_file_binding(file_to_process) diff --git a/gr-utils/modtool/core/disable.py b/gr-utils/modtool/core/disable.py index 2047a49935..9b2f428b31 100644 --- a/gr-utils/modtool/core/disable.py +++ b/gr-utils/modtool/core/disable.py @@ -78,41 +78,6 @@ class ModToolDisable(ModTool): cmake.comment_out_lines('GR_ADD_TEST.*'+os.path.splitext(fname)[0]) self.scm.mark_file_updated(cmake.filename) return True - def _handle_h_swig(cmake, fname): - """ Comment out include files from the SWIG file, - as well as the block magic """ - with open(self._file['swig']) as f: - swigfile = f.read() - (swigfile, nsubs) = re.subn(f'(.include\s+"({self.info["modname"]}/)?{fname}")', - r'//\1', swigfile) - if nsubs > 0: - logger.info(f"Changing {self._file['swig']}...") - if nsubs > 1: # Need to find a single BLOCK_MAGIC - blockname = os.path.splitext(fname[len(self.info['modname'])+1:])[0] - if self.info['version'] in ('37', '38'): - blockname = os.path.splitext(fname)[0] - (swigfile, nsubs) = re.subn(f'(GR_SWIG_BLOCK_MAGIC2?.+{blockname}.+;)', r'//\1', swigfile) - if nsubs > 1: - logger.warning(f"Hm, changed more then expected while editing {self._file['swig']}.") - with open(self._file['swig'], 'w') as f: - f.write(swigfile) - self.scm.mark_file_updated(self._file['swig']) - return False - def _handle_i_swig(cmake, fname): - """ Comment out include files from the SWIG file, - as well as the block magic """ - with open(self._file['swig']) as f: - swigfile = f.read() - blockname = os.path.splitext(fname[len(self.info['modname'])+1:])[0] - if self.info['version'] in ('37', '38'): - blockname = os.path.splitext(fname)[0] - swigfile = re.sub(r'(%include\s+"'+fname+'")', r'//\1', swigfile) - logger.info(f"Changing {self._file['swig']}...") - swigfile = re.sub('(GR_SWIG_BLOCK_MAGIC2?.+'+blockname+'.+;)', r'//\1', swigfile) - with open(self._file['swig'], 'w') as f: - f.write(swigfile) - self.scm.mark_file_updated(self._file['swig']) - return False # This portion will be covered by the CLI if not self.cli: @@ -123,10 +88,7 @@ class ModToolDisable(ModTool): special_treatments = ( ('python', r'qa.+py$', _handle_py_qa), ('python', r'^(?!qa).+py$', _handle_py_mod), - ('lib', r'qa.+\.cc$', _handle_cc_qa), - (f'include/{self.info["modname"]}', r'.+\.h$', _handle_h_swig), - ('include', r'.+\.h$', _handle_h_swig), - ('swig', r'.+\.i$', _handle_i_swig) + ('lib', r'qa.+\.cc$', _handle_cc_qa) ) for subdir in self._subdirs: if self.skip_subdirs[subdir]: diff --git a/gr-utils/modtool/core/rename.py b/gr-utils/modtool/core/rename.py index ac6f07215a..61f98b3722 100644 --- a/gr-utils/modtool/core/rename.py +++ b/gr-utils/modtool/core/rename.py @@ -62,25 +62,14 @@ class ModToolRename(ModTool): oldname = self.info['oldname'] newname = self.info['newname'] logger.info(f"In module '{module}' rename block '{oldname}' to '{newname}'") - self._run_swig_rename(self._file['swig'], oldname, newname) self._run_grc_rename(self.info['modname'], oldname, newname) self._run_python_qa(self.info['modname'], oldname, newname) self._run_python(self.info['modname'], oldname, newname) self._run_lib(self.info['modname'], oldname, newname) self._run_include(self.info['modname'], oldname, newname) + self._run_pybind(self.info['modname'], oldname, newname) return - def _run_swig_rename(self, swigfilename, old, new): - """ Rename SWIG includes and block_magic """ - nsubs = self._run_file_replace(swigfilename, old, new) - if nsubs < 1: - logger.info(f"Couldn't find '{old}' in file '{swigfilename}'.") - if nsubs == 2: - logger.info("Changing 'noblock' type file") - if nsubs > 3: - logger.warning(f"Hm, changed more then expected while editing {swigfilename}.") - return False - def _run_lib(self, module, old, new): ccfile = './lib/' + old + '_impl.cc' if not os.path.isfile(ccfile): # in case it is a 'noblock' @@ -129,6 +118,35 @@ class ModToolRename(ModTool): else: logger.info("Not a Python block, nothing to do here...") + def _run_pybind(self, module, old, new): + path = './python/bindings/' + filename = path + old + '_python.cc' + self._run_file_replace(filename, old, new) + self._run_file_rename(path, old, new) + self._run_cmakelists(path, old, new) + # update the hash in the new file + import hashlib + hasher = hashlib.md5() + header_filename = './include/' + module + '/' + new + '.h' # note this requires _run_pybind to be called after _run_include + with open(header_filename, 'rb') as file_in: + buf = file_in.read() + hasher.update(buf) + newhash = hasher.hexdigest() + newfilename = path + new + '_python.cc' + with open(newfilename) as f: + file_txt = f.read() + m = re.search(r'BINDTOOL_HEADER_FILE_HASH\(([^\s]*)\)', file_txt) + if (m): + oldhash = m.group(1) + file_txt = re.sub(oldhash, newhash, file_txt) + with open(newfilename, "w") as f: + f.write(file_txt) + + path = './python/bindings/docstrings/' + filename = path + old + '_pydoc_template.h' + self._run_file_replace(filename, old, new) + self._run_file_rename(path, old, new) + def _run_python_qa(self, module, old, new): new = 'qa_' + new old = 'qa_' + old diff --git a/gr-utils/modtool/core/rm.py b/gr-utils/modtool/core/rm.py index 6c0746aba4..b65465cd16 100644 --- a/gr-utils/modtool/core/rm.py +++ b/gr-utils/modtool/core/rm.py @@ -1,5 +1,5 @@ # -# Copyright 2013, 2018, 2019 Free Software Foundation, Inc. +# Copyright 2013, 2018-2020 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -18,7 +18,7 @@ import sys import glob import logging -from ..tools import remove_pattern_from_file, CMakeFileEditor +from ..tools import remove_pattern_from_file, CMakeFileEditor, CPPFileEditor from .base import ModTool, ModToolException logger = logging.getLogger(__name__) @@ -90,30 +90,31 @@ class ModToolRemove(ModTool): ed.delete_entry('GR_ADD_TEST', filebase) ed.remove_double_newlines() - def _make_swig_regex(filename): - filebase = os.path.splitext(filename)[0] - pyblockname = filebase.replace(self.info['modname'] + '_', '') - regexp = r'(^\s*GR_SWIG_BLOCK_MAGIC2?\({},\s*{}\);|^\s*.include\s*"({}/)?{}"\s*)'.format \ - (self.info['modname'], pyblockname, self.info['modname'], filename) - return regexp # Go, go, go! if not self.skip_subdirs['lib']: self._run_subdir('lib', ('*.cc', '*.h'), ('add_library', 'list'), cmakeedit_func=_remove_cc_test_case) if not self.skip_subdirs['include']: incl_files_deleted = self._run_subdir(self.info['includedir'], ('*.h',), ('install',)) - if not self.skip_subdirs['swig']: - swig_files_deleted = self._run_subdir('swig', ('*.i',), ('install',)) - for f in incl_files_deleted + swig_files_deleted: - # TODO do this on all *.i files - remove_pattern_from_file(self._file['swig'], _make_swig_regex(f)) - self.scm.mark_file_updated(self._file['swig']) if not self.skip_subdirs['python']: py_files_deleted = self._run_subdir('python', ('*.py',), ('GR_PYTHON_INSTALL',), cmakeedit_func=_remove_py_test_case) for f in py_files_deleted: remove_pattern_from_file(self._file['pyinit'], fr'.*import\s+{f[:-3]}.*') remove_pattern_from_file(self._file['pyinit'], fr'.*from\s+{f[:-3]}\s+import.*\n') + + pb_files_deleted = self._run_subdir('python/bindings', ('*.cc',), ('list',)) + + pbdoc_files_deleted = self._run_subdir('python/bindings/docstrings', ('*.h',), ('',)) + + # Update python_bindings.cc + ed = CPPFileEditor(self._file['ccpybind']) + ed.remove_value('// BINDING_FUNCTION_PROTOTYPES(', '// ) END BINDING_FUNCTION_PROTOTYPES', + 'void bind_' + self.info['blockname'] + '(py::module& m);') + ed.remove_value('// BINDING_FUNCTION_CALLS(', '// ) END BINDING_FUNCTION_CALLS', + 'bind_' + self.info['blockname'] + '(m);') + ed.write() + if not self.skip_subdirs['grc']: self._run_subdir('grc', ('*.yml',), ('install',)) @@ -132,7 +133,7 @@ class ModToolRemove(ModTool): for g in globs: files = files + sorted(glob.glob(f"{path}/{g}")) files_filt = [] - logger.info("Searching for matching files in {path}/:") + logger.info(f"Searching for matching files in {path}/:") for f in files: if re.search(self.info['pattern'], os.path.basename(f)) is not None: files_filt.append(f) @@ -141,7 +142,6 @@ class ModToolRemove(ModTool): return [] # 2. Delete files, Makefile entries and other occurrences files_deleted = [] - ed = CMakeFileEditor(f'{path}/CMakeLists.txt') yes = self.info['yes'] for f in files_filt: b = os.path.basename(f) @@ -157,11 +157,15 @@ class ModToolRemove(ModTool): logger.info(f"Deleting {f}.") self.scm.remove_file(f) os.unlink(f) - logger.info(f"Deleting occurrences of {b} from {path}/CMakeLists.txt...") - for var in makefile_vars: - ed.remove_value(var, b) - if cmakeedit_func is not None: - cmakeedit_func(b, ed) - ed.write() - self.scm.mark_files_updated((f'{path}/CMakeLists.txt')) + + if (os.path.exists(f'{path}/CMakeLists.txt')): + ed = CMakeFileEditor(f'{path}/CMakeLists.txt') + logger.info(f"Deleting occurrences of {b} from {path}/CMakeLists.txt...") + for var in makefile_vars: + ed.remove_value(var, b) + if cmakeedit_func is not None: + cmakeedit_func(b, ed) + ed.write() + self.scm.mark_files_updated((f'{path}/CMakeLists.txt')) + return files_deleted |