Инструмент для синхронизации разветвленного и реорганизованного кода C++?

Я ищу инструмент Windows GUI/командной строки или подключаемый модуль Visual Studio, где я могу автоматизировать извлечение блоков кода C++, добавить некоторые шаги рефакторинга/переименования и вставить его в какой-либо другой файл C++. После того, как это настроено, я хочу синхронизировать источник/назначение блоков кода и/или проверять различия.

РЕДАКТИРОВАТЬ : я стараюсь, чтобы в моем проекте все было как можно проще. Поэтому я надеюсь на решение с низким уровнем сложности. Я бы предпочел решение, использующее несколько однозадачных инструментов (возможно, уже поставляемых с моей ОС/IDE/SCM), а не многофункциональный многозадачный инструмент, созданный для обработки гораздо большего количества задач.

Пример

Чтобы привести очень простой пример - и я не уверен, что рассматриваемому инструменту даже нужно понимать синтаксис C++ для выполнения чего-то подобного:

OldClass.cpp

class OldClass
{
public:
   ...
   void MyFunctionToReuse()
   {
       ...
       // Start OldClass::MyFunctionToReuse() block
       mVarOldName = ...;
       // End OldClass::MyFunctionToReuse() block
       ...
   }
};

NewClass.cpp

class NewClass
{
public:
   ...
   void SomeFunction()
   {
       ...
       // Start OldClass::MyFunctionToReuse() block
       // file OldClass.cpp, line 100 - 110
       // renamed mVarOldName to mVarNewName
       mVarNewName = ...;
       // End OldClass::MyFunctionToReuse() block
       ...
   }
};

Возможности, которые я сейчас вижу

Я вижу четыре возможных способа сделать это:

  1. Вручную извлеките код, который я хочу повторно использовать, в шаблоны/классы/функции C++
  2. Используйте инструменты рефакторинга C++ с функцией записи макросов
  3. Используйте транспилятор с набором правил для преобразования OldClassвNewClass
  4. Подход, основанный только на текстовом инструменте, ищет ключевые слова в комментариях (копировать/переименовать/отличить/вставить)

Обоснование

У меня есть длительный проект C++ модели/представления/контроллера, в котором часть представления теперь должна быть заменена/перемещена в отдельное приложение. Старая кодовая база может использоваться повторно на 80%, но я не могу использовать классы в том виде, в каком они есть сейчас. Итак, я сейчас нахожусь в точке, где я отхожу от своего старого проекта, чтобы начать новый код.

Но старый проект все равно будет поддерживаться в течение нескольких лет. Поэтому, если я начну с необходимых изменений для / рефакторинга нового проекта, я ищу что-то, чтобы синхронизировать оба потока/ветви кода (в основном для исправления ошибок).

И огромные изменения в старом продукте — это только крайняя мера, потому что это означало бы — даже при хорошем покрытии кода модульными тестами — повторное тестирование основных частей поставляемого в настоящее время продукта.

Что я изучил до сих пор

Списки функций

(Я парень позади DMS). Почему вы думаете, что они "негабаритные"? C++ невероятно сложный язык. Если вы хотите манипулировать им механически, механизм должен каким-то образом справиться со всей сложностью, иначе он не будет делать то, что вы хотите, или сделает это неправильно. Как бы вы предложили существование более простого механизма? [PS: DMS позволяет вам писать правила преобразования источника в источник и запускать их в повторяемом порядке; это по сути то, что вы ищете как «запись макроса»]
@IraBaxter Я признаю, что часть моего вопроса носит философский характер. И я приверженец принципа KISS (соответственно обновлю вопрос). Тем не менее, я стесняюсь использовать DMS из-за его очень впечатляющего набора функций. Внедрение сложных инструментов в ваш проект буквально требует цены (покупка, обучение, обслуживание). Поэтому в случае сложной проблемы я склонен разбивать проблему на менее сложные части, а не использовать более сложные инструменты для обработки всего.
Я абсолютно согласен с тем, что использование сложного инструмента имеет свою цену, и хорошо, что вы это понимаете. При прочих равных вы хотите избежать этого. Суть в том, есть ли у вас достаточно сложная проблема с достаточным обоснованием. Не стесняйтесь исследовать альтернативы. Если ваша проблема включает какие-либо явные манипуляции с кодом, я сомневаюсь, что удастся избежать чего-то вроде DMS, и поэтому остается решить, насколько важно реализовать ваше видение.
@IraBaxter Спасибо за совет. И да, я думаю, в конце концов, если я хочу, чтобы шаги манипуляции были простыми, все будет зависеть от наличия только локализованных/минимальных изменений кода.
Это звучит как то, что вы не должны делать. Сохраните реализацию и вместо этого напишите класс адаптера или аналогичный.

Ответы (1)

В итоге я использовал предварительный компилятор Visual Studio для перевода моих исходных файлов с помощью определений макросов. На втором этапе я использую PowerShell для замены/добавления некоторых специальных символов форматирования, которые прекомпилятор удалит/проигнорирует.

Поскольку я использую CMake, вот протестированный мной скрипт:

cmake_minimum_required(VERSION 2.8.9)

project(CppTranslationDemo)

if(NOT MSVC_VERSION GREATER 1699)
    message(FATAL_ERROR "Only tested with VS2012 or above")
endif()

set(
    inFiles
    OldClass.cpp
)
unset(outFiles)

find_program(
    POWERSHELL_EXE
        NAMES powershell.exe
        PATHS C:/Windows/System32
        PATH_SUFFIXES WindowsPowerShell/v1.0
)
if (NOT POWERSHELL_EXE)
    message(FATAL_ERROR "Couldn't find powershell.exe")
endif()

foreach(_file IN ITEMS ${inFiles})
    file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" _file_native_path)
    file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/TranslationMacros.h" _macro_file_native_path)
    file(TO_NATIVE_PATH "${CMAKE_CXX_COMPILER}" _compiler_native_path)

    get_filename_component(_file_name "${_file}" NAME)
    get_filename_component(_file_ext "${_file}" EXT)

    string(REPLACE "Old" "New" _file_name "${_file_name}")
    set(_out_file "${CMAKE_BINARY_DIR}/${_file_name}")

    set(
        _powershell_cmd_list
        "$i = 1;"
        # NOTE: increase column width to prevent word wrap after 80 chararcters
        "$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size (500, 25);"
        "$nl = [Environment]::NewLine;"
        "& '${_compiler_native_path}' /nologo /EP /C /FI${_macro_file_native_path} ${_file_native_path}"
        "|"
        "Foreach-Object"
        "{"
            "$_"
            "-replace '@NL@', $nl"
            "-replace '@TAB@', '    '"
            "-replace '@H@', '#'"
            "-replace '@C@', '//'"
            "-replace '@CB@', '/*'"
            "-replace '@CE@', '*/'"
            "-replace '@.*@', ''"
        "}"
        "|"
        "where"
        "{"
            "if ($_ -eq '')"
            "{" 
                "$i++;" 
            "}" 
            "else"
            "{" 
                "$i = 0;" 
            "}"
            "($i -lt 2)"
        "};"
        "exit $LASTEXITCODE"
    )
    string(REGEX REPLACE ";([^;])" " \\1" _powershell_cmd "${_powershell_cmd_list}")

    add_custom_command(
        OUTPUT          ${_out_file} 
        COMMAND         "${POWERSHELL_EXE}" -Command "${_powershell_cmd}" 1> "${_out_file}"
        DEPENDS         ${_file}
                        TranslationMacros.h
        COMMENT         "${_out_file}"
    )

    list(APPEND outFiles "${_out_file}")
endforeach() 

add_custom_target(
    ${PROJECT_NAME}
        DEPENDS ${outFiles}
        SOURCES 
            TranslationMacros.h
            ${inFiles}
)
set_source_files_properties(${outFiles} PROPERTIES GENERATED 1)

add_library(
    ${PROJECT_NAME}Test
    ${outFiles} 
)
add_dependencies(
    ${PROJECT_NAME}Test
    ${PROJECT_NAME}
)

В сочетании с

ПереводMacros.h

#define OldClass            NewClass
#define MyFunctionToReuse   SomeFunction
#define mVarOldName         mVarNewName 

Переводит

OldClass.cpp

class OldClass
{
public:
   OldClass() : mVarOldName(0) {}

   void MyFunctionToReuse()
   {
       // Some test comment
       mVarOldName = 1;
   }

   int mVarOldName;
};

В

NewClass.cpp

class NewClass
{
public:
   NewClass() : mVarNewName(0) {}

   void SomeFunction()
   {
       // Some test comment
       mVarNewName = 1;
   }

   int mVarNewName;
};

использованная литература

Визуальная студия

PowerShell

Вы также можете принять свой собственный ответ, который поможет другим, кто прочитает этот вопрос в будущем.