├── test ├── datatest │ ├── sln │ │ ├── test1.F90 │ │ ├── cpp.sln │ │ ├── cpp_and_fortran.sln │ │ └── bar.vfproj │ ├── additional_code_test.cmake │ ├── external │ │ ├── g3logmain.cpp │ │ ├── zlib.h │ │ ├── zlib.cpp │ │ ├── g3log.vcxproj.filters │ │ ├── zlib.vcxproj.filters │ │ └── g3log.vcxproj │ └── foosrc │ │ └── main.cpp ├── .coveragerc ├── requirements.txt ├── setup_test.sh ├── test_flags.py ├── test_utils.py ├── test_dependencies.py ├── test_data_files.py ├── test_data_converter.py ├── test_project_files.py └── test_project_variables.py ├── requirements.txt ├── readthedocs.yml ├── setup.cfg ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ └── bug_report.md ├── MANIFEST.in ├── make_and_upload_wheel.bat ├── .landscape.yml ├── .gitignore ├── docs ├── index.rst ├── install.rst ├── api.rst ├── intro.rst ├── use.rst ├── cmake.rst ├── Makefile ├── make.bat └── conf.py ├── cmake_converter ├── visual_studio │ ├── DefaultCXX.cmake │ ├── DefaultFortran.cmake │ ├── vcxproj │ │ ├── project_files.py │ │ ├── utils.py │ │ └── project_variables.py │ ├── vfproj │ │ ├── utils.py │ │ ├── project_variables.py │ │ ├── project_files.py │ │ ├── dependencies.py │ │ └── parser.py │ ├── context.py │ └── Default.cmake ├── __init__.py ├── flags.py ├── dependencies.py ├── parser.py ├── main.py ├── project_variables.py ├── context.py ├── data_files.py ├── project_files.py ├── utils.cmake └── data_converter.py ├── .travis.yml ├── setup.py └── README.rst /test/datatest/sln/test1.F90: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | colorama 2 | lxml 3 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | python: 2 | version: 3.6 3 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.rst 3 | -------------------------------------------------------------------------------- /test/datatest/additional_code_test.cmake: -------------------------------------------------------------------------------- 1 | set(ADD_CODE code) -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ["https://www.paypal.me/pavelliavonau"] 2 | -------------------------------------------------------------------------------- /test/datatest/external/g3logmain.cpp: -------------------------------------------------------------------------------- 1 | static const char* g3lob_var = "hello"; -------------------------------------------------------------------------------- /test/datatest/external/zlib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int foo(); 4 | int bar(); -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | recursive-include cmake_converter *.* 3 | global-exclude *pyc -------------------------------------------------------------------------------- /test/.coveragerc: -------------------------------------------------------------------------------- 1 | [report] 2 | exclude_lines = 3 | pragma: no cover 4 | 5 | [run] 6 | source = 7 | cmake_converter -------------------------------------------------------------------------------- /test/datatest/foosrc/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "zlib.h" 3 | 4 | int main() 5 | { 6 | std::cout << "hello world!" << std::endl; 7 | } -------------------------------------------------------------------------------- /test/requirements.txt: -------------------------------------------------------------------------------- 1 | # Python requirements for unit tests 2 | unittest2 3 | pytest 4 | pytest-cov 5 | coverage 6 | coveralls 7 | pycodestyle 8 | pep257 9 | future 10 | pylint -------------------------------------------------------------------------------- /test/datatest/external/zlib.cpp: -------------------------------------------------------------------------------- 1 | #include "zlib.h" 2 | 3 | static const char* zlib_var = "hello"; 4 | 5 | int foo() 6 | { 7 | return 0; 8 | } 9 | 10 | int bar() 11 | { 12 | return 1; 13 | } -------------------------------------------------------------------------------- /make_and_upload_wheel.bat: -------------------------------------------------------------------------------- 1 | python setup.py sdist bdist_wheel 2 | 3 | rem test uploading 4 | twine upload --repository-url https://test.pypi.org/legacy/ dist/* 5 | 6 | rem release uploading 7 | rem twine upload dist/* 8 | 9 | @pause -------------------------------------------------------------------------------- /.landscape.yml: -------------------------------------------------------------------------------- 1 | doc-warnings: true 2 | test-warnings: false 3 | strictness: medium 4 | max-line-length: 100 5 | autodetect: true 6 | pep8: 7 | full: true 8 | requirements: 9 | - requirements.txt 10 | - test/requirements.txt 11 | python-targets: 12 | - 3 13 | pyflakes: 14 | disable: 15 | - F821 16 | ignore-paths: 17 | - docs 18 | - test 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python file 2 | *.pyc 3 | __pycache__/ 4 | *.egg-info 5 | dist/ 6 | 7 | # IDE 8 | *.swp 9 | .idea/ 10 | *.user 11 | *.suo 12 | *.db 13 | *.opendb 14 | *.db-shm 15 | *.db-wal 16 | *.log 17 | *.tlog 18 | 19 | # Build 20 | build/ 21 | *.obj 22 | *.lib 23 | *.idb 24 | *.pdb 25 | *.u2d 26 | BuildLog.htm 27 | 28 | # Tests/Coverage 29 | .coverage 30 | .pytest_cache/ 31 | 32 | # Docs 33 | _static 34 | _build 35 | 36 | # Misc 37 | #*.cmake 38 | CMakeLists.txt 39 | Utils.cmake 40 | -------------------------------------------------------------------------------- /test/datatest/external/g3log.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {519eef24-9d46-4a51-9358-57146f67feed} 6 | 7 | 8 | 9 | 10 | Test Sources 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. cmake_converter documentation master file, created by 2 | sphinx-quickstart on Mon Oct 23 12:02:46 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to CMake Converter's documentation 7 | ****************************************** 8 | 9 | Documentation Content: 10 | 11 | .. toctree:: 12 | :maxdepth: 3 13 | 14 | intro 15 | install 16 | use 17 | cmake 18 | api 19 | 20 | 21 | Indices and tables 22 | ****************** 23 | 24 | * :ref:`genindex` 25 | * :ref:`modindex` 26 | * :ref:`search` 27 | 28 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/DefaultCXX.cmake: -------------------------------------------------------------------------------- 1 | include("${CMAKE_CURRENT_LIST_DIR}/Default.cmake") 2 | 3 | set_config_specific_property("OUTPUT_DIRECTORY" "${CMAKE_SOURCE_DIR}$<$>:/${CMAKE_VS_PLATFORM_NAME}>/${PROPS_CONFIG}") 4 | 5 | if(MSVC) 6 | create_property_reader("DEFAULT_CXX_EXCEPTION_HANDLING") 7 | create_property_reader("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT") 8 | 9 | set_target_properties("${PROPS_TARGET}" PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") 10 | set_config_specific_property("DEFAULT_CXX_EXCEPTION_HANDLING" "/EHsc") 11 | set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi") 12 | endif() 13 | -------------------------------------------------------------------------------- /test/datatest/external/zlib.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {000f37f3-c5d5-448d-a825-ec696463ce53} 6 | 7 | 8 | {01a4a966-1b3d-4dd0-9de3-81f1d139be01} 9 | 10 | 11 | 12 | 13 | Test Sources 14 | 15 | 16 | 17 | 18 | Headers 19 | 20 | 21 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/DefaultFortran.cmake: -------------------------------------------------------------------------------- 1 | include("${CMAKE_CURRENT_LIST_DIR}/Default.cmake") 2 | 3 | set_config_specific_property("OUTPUT_DIRECTORY" "${CMAKE_CURRENT_SOURCE_DIR}$<$>:/${CMAKE_VS_PLATFORM_NAME}>/${PROPS_CONFIG}") 4 | 5 | get_target_property(${PROPS_TARGET}_BINARY_DIR ${PROPS_TARGET} BINARY_DIR) 6 | set(DEFAULT_FORTRAN_MODULES_DIR "${${PROPS_TARGET}_BINARY_DIR}/${PROPS_TARGET}.Modules.dir") 7 | set_target_properties(${PROPS_TARGET} PROPERTIES Fortran_MODULE_DIRECTORY ${DEFAULT_FORTRAN_MODULES_DIR}) 8 | 9 | if(${CMAKE_GENERATOR} MATCHES "Visual Studio") 10 | # Hack for visual studio generator (https://gitlab.kitware.com/cmake/cmake/issues/19552) 11 | add_custom_command(TARGET ${PROPS_TARGET} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory $/${CMAKE_CFG_INTDIR}) 12 | endif() -------------------------------------------------------------------------------- /docs/install.rst: -------------------------------------------------------------------------------- 1 | .. _install: 2 | 3 | Install CMake Converter 4 | *********************** 5 | 6 | Requirements 7 | ============ 8 | 9 | You must have **Python 3** installed to make this library work. 10 | 11 | **Note:** CMake Converter is **not compatible** with Python 2 ! 12 | 13 | Installation (from Pip) 14 | ======================= 15 | 16 | You can install cmake-converter as a standard python library, with ``pip``:: 17 | 18 | pip install cmake_converter 19 | 20 | Install last pre-release or development version of cmake-converter:: 21 | 22 | pip install --pre cmake_converter 23 | 24 | Installation (from Sources) 25 | =========================== 26 | 27 | Clone and install 28 | ----------------- 29 | 30 | To install from sources, you've to clone this repository and make a pip install:: 31 | 32 | git clone https://github.com/algorys/cmakeconverter.git 33 | cd cmakeconverter 34 | pip install . 35 | 36 | External Libraries 37 | ------------------ 38 | 39 | You need to install Python modules that are listed in ``requirements.txt`` file with pip: 40 | 41 | .. literalinclude:: ../requirements.txt -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | API Documentation 4 | ***************** 5 | 6 | .. automodule:: cmake_converter.data_converter 7 | :members: 8 | :inherited-members: 9 | :show-inheritance: 10 | .. automodule:: cmake_converter.context 11 | :members: 12 | :inherited-members: 13 | :show-inheritance: 14 | .. automodule:: cmake_converter.data_files 15 | :members: 16 | :inherited-members: 17 | :show-inheritance: 18 | .. automodule:: cmake_converter.dependencies 19 | :members: 20 | :undoc-members: 21 | :inherited-members: 22 | :show-inheritance: 23 | .. automodule:: cmake_converter.flags 24 | :members: 25 | :undoc-members: 26 | :inherited-members: 27 | :show-inheritance: 28 | .. automodule:: cmake_converter.project_files 29 | :members: 30 | :undoc-members: 31 | :inherited-members: 32 | :show-inheritance: 33 | .. automodule:: cmake_converter.project_variables 34 | :members: 35 | :undoc-members: 36 | :inherited-members: 37 | :show-inheritance: 38 | .. automodule:: cmake_converter.utils 39 | :members: 40 | :undoc-members: 41 | :inherited-members: 42 | :show-inheritance: 43 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: true 3 | python: 4 | - "3.6" 5 | - "3.7" 6 | - "3.8" 7 | - "3.9" 8 | 9 | install: 10 | - ./test/setup_test.sh 11 | 12 | script: 13 | # so to help eventual debug: knowing what exact versions are in use can be rather useful. 14 | - pip freeze 15 | # Code static analysis 16 | - pycodestyle --max-line-length=100 --exclude='.pyc,.cfg,.log,.cmake' --ignore='E402,W503' cmake_converter/ 17 | - pylint --rcfile=.pylintrc cmake_converter/ cmake_converter/visual_studio 18 | # No pep257 currently (Code doc compliance) 19 | - pep257 --select=D300 cmake_converter 20 | # Code dynamic analysis 21 | - cd test/ 22 | - coverage erase 23 | - pytest --cov=cmake_converter --cov-config=.coveragerc test_*.py 24 | - coverage report -m 25 | - cd .. 26 | 27 | 28 | # specific call to launch coverage data into coveralls.io 29 | after_success: 30 | # to get coverage data with relative paths and not absolute we have to 31 | # execute coveralls from the base directory of the project, 32 | # so we need to move the .coverage file here : 33 | - mv test/.coverage . && coveralls --rcfile=test/.coveragerc -v 34 | # - coveralls -v 35 | 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **IMPORTANT**: always check already known open issues before creating new one. Your issue might be already reported. 11 | 12 | Do not create and name issues like *"IndexError: tuple index out of range"*. Do investigation and name it properly. 13 | 14 | **Describe the bug** 15 | 1. A clear and concise description of what the bug is. 16 | 2. Which is version of converter. python? 17 | 3. Increase warnings level (-w4) and attach verbose (-v) output log to help investigate what was happen. Use one thread to get the logs to make them easy to read(-j1). 18 | 4. Also the sample of input xml project(or full solution (might be without code)) and output CMakeLists part wrong content is required. I don't have much time for digging into it. So with more info I can help you easily. 19 | 20 | **To Reproduce** 21 | Steps to reproduce the behavior: 22 | 1. Call string of converter 23 | 2. See error 24 | 3. .. any other steps. 25 | 26 | **Expected behavior** 27 | A clear and concise description of what you expected to happen. 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/vcxproj/project_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Module for project files properties for C/C++ projects 25 | """ 26 | 27 | from cmake_converter.project_files import ProjectFiles 28 | 29 | 30 | class VCXProjectFiles(ProjectFiles): 31 | """ 32 | Class project files properties for C/C++ projects 33 | """ 34 | -------------------------------------------------------------------------------- /docs/intro.rst: -------------------------------------------------------------------------------- 1 | .. _intro: 2 | 3 | Introduction 4 | ************ 5 | 6 | About CMake Converter 7 | ===================== 8 | 9 | CMake Converter is an open source software written in Python under the terms of the `GNU Affero General Public License `_ . 10 | 11 | This application is for developers and integrators who want to automate the creation of ``CMakeLists.txt`` for their build systems from Visual Studio solution files. 12 | 13 | Features 14 | ======== 15 | 16 | CMake Converter converts your ``*.sln`` file (``vcxproj`` and ``vfproj`` are supported only) into corresponding tree of ``CMakeLists.txt``. 17 | It tries to translate data such as compile and link flags, project files, project dependencies, outputs of the produced binaries and more into CMake language. 18 | 19 | Release cycle 20 | ============= 21 | 22 | CMake Converter has no strict schedule for releasing. 23 | 24 | Other features will come in the next versions and you can propose new features through `project issues `_. 25 | Each feature is discussed in a separate issue. 26 | 27 | About CMake 28 | =========== 29 | 30 | In this documentation, you'll find some reminders about CMake and how the script handles your project's data inside. 31 | For example, how the generated **CMakeLists.txt** manage dependencies. 32 | 33 | But a minimum of knowledge on `CMake `_ is **recommended** ! 34 | -------------------------------------------------------------------------------- /test/setup_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) 2016-2019: 4 | # Matthieu Estrada, ttamalfor@gmail.com 5 | # Pavel Liavonau, liavonlida@gmail.com 6 | # 7 | # This file is part of (CMakeConverter). 8 | # 9 | # (CMakeConverter) is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU Affero General Public License as published by 11 | # the Free Software Foundation, either version 3 of the License, or 12 | # (at your option) any later version. 13 | # 14 | # (CMakeConverter) is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU Affero General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU Affero General Public License 20 | # along with (CMakeConverter). If not, see . 21 | 22 | set -e 23 | 24 | THIS_PATH=$(dirname "$0") 25 | BASE_PATH=$(dirname "$THIS_PATH") 26 | 27 | cd $BASE_PATH 28 | 29 | echo '--------- Upgrade pip ... --------- ' 30 | pip install --upgrade pip 31 | 32 | echo '--------- Installing application requirements ... --------- ' 33 | pip install -r requirements.txt 34 | 35 | echo '--------- Installing application in development mode ... --------- ' 36 | pip install -e . 37 | 38 | echo '--------- Installing tests requirements ... --------- ' 39 | pip install --upgrade -r test/requirements.txt 40 | -------------------------------------------------------------------------------- /test/test_flags.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | import os 24 | import unittest 25 | 26 | from cmake_converter.visual_studio.context import VSContext 27 | from cmake_converter.data_converter import DataConverter 28 | 29 | 30 | class TestFlags(unittest.TestCase): 31 | """ 32 | This file test methods of Flags class. 33 | """ 34 | 35 | def setUp(self): 36 | cur_dir = os.path.dirname(os.path.realpath(__file__)) 37 | context = VSContext() 38 | context.verbose = False 39 | vs_project = '{}/datatest/foo.vcxproj'.format(cur_dir) 40 | context.cmake = './' 41 | converter = DataConverter() 42 | converter.convert_project(context, vs_project, cur_dir) 43 | 44 | -------------------------------------------------------------------------------- /test/test_utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | import unittest 24 | 25 | from cmake_converter.writer import CMakeWriter 26 | 27 | 28 | class TestUtils(unittest.TestCase): 29 | """ 30 | This file test methods of utils package 31 | """ 32 | 33 | def test_get_title(self): 34 | """Get Comment""" 35 | 36 | under_test = CMakeWriter.get_comment('text of comment') 37 | 38 | self.assertEqual( 39 | '################################################################################\n' 40 | '# text of comment\n' 41 | '################################################################################\n', 42 | under_test 43 | ) 44 | 45 | 46 | if __name__ == '__main__': 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /docs/use.rst: -------------------------------------------------------------------------------- 1 | .. _use: 2 | 3 | Use CMake Converter 4 | ******************* 5 | 6 | Quick Use 7 | ========= 8 | 9 | To use cmake converter, simply give your ``*.sln`` file to cmake-converter command:: 10 | 11 | cmake-converter -s 12 | 13 | Advance Usage 14 | ============= 15 | 16 | The ``cmake-converter`` command accepts a lot of parameters to try to suit the majority of situations. 17 | 18 | .. automodule:: cmake_converter.main 19 | 20 | Solution Conversion 21 | =================== 22 | 23 | With cmake-converter, you can convert full Visual Studio solutions. 24 | 25 | The script will extract data from all supported \*proj files and create the corresponding **CMakeLists.txt**. 26 | 27 | 28 | With the following project structure:: 29 | 30 | project/ 31 | └── msvc 32 | ├── libone 33 | │   └── libone.vcxproj 34 | ├── libtwo 35 | │   └── libtwo.vcxproj 36 | └── myexec 37 | ├── myexec.sln 38 | └── myexec.vcxproj 39 | 40 | Then you'll run cmake-converter as follow: 41 | 42 | .. code-block:: bash 43 | 44 | cmake-converter \ 45 | --solution=project/msvc/myexec/myexec.sln \ 46 | --verbose-mode \ 47 | --private-include-directories \ 48 | --warning-level=3 49 | 50 | And you'll have the following CMakeLists.txt generated:: 51 | 52 | project/ 53 | └── msvc 54 | ├── libone 55 | │   ├── CMakeLists.txt * 56 | │   └── libone.vcxproj 57 | ├── libtwo 58 | │   ├── CMakeLists.txt * 59 | │   └── libtwo.vcxproj 60 | └── myexec 61 | │   62 |    └── CMake * 63 | │ ├── Default*.cmake * 64 | │ └── Utils.cmake * 65 | ├── CMakeLists.txt * 66 | ├── myexec.sln 67 | └── myexec.vcxproj 68 | 69 | Hints 70 | ===== 71 | 72 | You can add CMake/GlobalSettingsInclude.cmake file for global custom CMake settings. 73 | 74 | Pay attention on warnings and do proposed fixes. 75 | 76 | Run cmake-converter --help for more info. 77 | -------------------------------------------------------------------------------- /cmake_converter/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | CMakeConverter 25 | 26 | This module is a command line program who allow you to convert .vcxproj file 27 | to CMakeLists.txt file. 28 | """ 29 | 30 | # Application version and manifest 31 | VERSION = (2, 2, 0) 32 | __application__ = "CMake-Converter" 33 | __short_version__ = '.'.join((str(each) for each in VERSION[:2])) 34 | __version__ = '.'.join((str(each) for each in VERSION[:4])) 35 | __author__ = "Liavonau Pavel" 36 | __copyright__ = "2016-2020 - %s" % __author__ 37 | __license__ = "GNU Affero General Public License, version 3" 38 | __description__ = "CMake converter for Visual Studio projects" 39 | __releasenotes__ = "CMake converter for Visual Studio projects" 40 | __project_url__ = "https://github.com/pavelliavonau/cmakeconverter" 41 | __doc_url__ = "https://github.com/pavelliavonau/cmakeconverter" 42 | 43 | # Application Manifest 44 | manifest = { 45 | 'name': __application__, 46 | 'version': __version__, 47 | 'author': __author__, 48 | 'description': __description__, 49 | 'copyright': __copyright__, 50 | 'license': __license__, 51 | 'release': __releasenotes__, 52 | 'url': __project_url__, 53 | 'doc': __doc_url__ 54 | } 55 | -------------------------------------------------------------------------------- /cmake_converter/flags.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Flags 25 | ===== 26 | Manage compilation flags of project 27 | """ 28 | 29 | cl_flags = 'cl_flags' # MSVC compile flags (Windows only) 30 | ln_flags = 'ln_flags' # MSVC link flags (Windows only) 31 | ifort_cl_win = 'ifort_cl_win' # ifort compile flags (Windows) 32 | ifort_cl_unix = 'ifort_cl_unix' # ifort compile flags (Unix) 33 | ifort_ln_win = 'ifort_ln_win' # ifort link flags for windows 34 | ifort_ln_unix = 'ifort_ln_unix' # ifort link flags for unix 35 | defines = 'defines' # compile definitions (cross platform) 36 | default_value = 'default_value' 37 | 38 | 39 | # pylint: disable=R0903 40 | 41 | class Flags: 42 | """ 43 | Class who manage flags of projects 44 | """ 45 | 46 | @staticmethod 47 | def get_no_default_lib_link_flags(flag_value): 48 | """Helper to get list of /NODEFAULTLIB flags""" 49 | ignore_libs = [] 50 | if flag_value != '': 51 | for spec_lib in flag_value.split(';'): 52 | spec_lib = spec_lib.strip() 53 | if spec_lib: 54 | ignore_libs.append('/NODEFAULTLIB:' + spec_lib) 55 | return ignore_libs 56 | 57 | # pylint: enable=R0903 58 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/vcxproj/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Module for special utils for C/C++ projects 25 | """ 26 | 27 | from cmake_converter.utils import Utils 28 | 29 | 30 | class VCXUtils(Utils): 31 | """ 32 | Class for special utils for C/C++ projects 33 | """ 34 | 35 | def lists_of_settings_to_merge(self): 36 | lists = super().lists_of_settings_to_merge() 37 | lists.extend( 38 | [ 39 | 'cl_flags', 40 | 'ln_flags', 41 | 'MSVC_RUNTIME_LIBRARY', 42 | 'COMMON_LANGUAGE_RUNTIME' 43 | ] 44 | ) 45 | return lists 46 | 47 | def init_context_current_setting(self, context): 48 | """ 49 | Define settings of converter. 50 | 51 | :param context: converter context 52 | :type context: Context 53 | """ 54 | 55 | super().init_context_current_setting(context) 56 | for list_to_merge in self.lists_of_settings_to_merge(): 57 | context.settings[context.current_setting][list_to_merge] = [] 58 | context.settings[context.current_setting]['inc_dirs_list'] = [] 59 | context.settings[context.current_setting]['PrecompiledHeader'] = [] 60 | context.settings[context.current_setting]['MSVC_RUNTIME_LIBRARY'] = [] 61 | context.settings[context.current_setting]['COMMON_LANGUAGE_RUNTIME'] = [] 62 | context.settings[context.current_setting]['property_sheets'] = [] 63 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/vfproj/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Utils for fortran projects (*.vfproj) 25 | """ 26 | 27 | from cmake_converter.utils import Utils 28 | 29 | 30 | class VFUtils(Utils): 31 | """ 32 | CLass of utils for fortran projects (*.vfproj) 33 | """ 34 | 35 | def lists_of_settings_to_merge(self): 36 | lists = super().lists_of_settings_to_merge() 37 | lists.extend( 38 | [ 39 | 'ifort_cl_win', 40 | 'ifort_cl_unix', 41 | 'ifort_ln_win', 42 | 'ifort_ln_unix', 43 | ] 44 | ) 45 | return lists 46 | 47 | def init_context_current_setting(self, context): 48 | """ 49 | Define settings of converter. 50 | 51 | :param context: converter context 52 | :type context: Context 53 | """ 54 | 55 | super().init_context_current_setting(context) 56 | for list_to_merge in self.lists_of_settings_to_merge(): 57 | context.settings[context.current_setting][list_to_merge] = [] 58 | if None not in context.current_setting: 59 | context.settings[context.current_setting]['inc_dirs'] = ['${CMAKE_CURRENT_SOURCE_DIR}/'] 60 | context.settings[context.current_setting]['inc_dirs_list'] = ['./'] 61 | context.settings[context.current_setting]['assume_args'] = [] 62 | context.settings[context.current_setting]['warn_args'] = [] 63 | context.settings[context.current_setting]['check_args'] = [] 64 | context.settings[context.current_setting]['target_type'] = 'Application' 65 | context.settings[context.current_setting]['Fortran_MODULE_DIRECTORY'] = [] 66 | -------------------------------------------------------------------------------- /test/test_dependencies.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | import os 24 | import unittest 25 | 26 | from cmake_converter.visual_studio.context import VSContext 27 | from cmake_converter.visual_studio.solution import VSSolutionConverter 28 | 29 | 30 | class TestDependencies(unittest.TestCase): 31 | """ 32 | This file test methods of Dependencies class. 33 | """ 34 | 35 | cur_dir = os.path.dirname(os.path.realpath(__file__)) 36 | 37 | def setUp(self): 38 | self.context = VSContext() 39 | self.context.verbose = False 40 | solution_file = '{}/datatest/sln/cpp.sln'.format(self.cur_dir) 41 | converter = VSSolutionConverter() 42 | converter.convert_solution(self.context, os.path.abspath(solution_file)) 43 | 44 | def test_write_include_dir(self): 45 | """Write Include Dirs""" 46 | 47 | with open(self.cur_dir + '/datatest/CMakeLists.txt') as cmake_lists_test: 48 | cmake_content = cmake_lists_test.read() 49 | self.assertTrue( 50 | '${CMAKE_CURRENT_SOURCE_DIR}/external' in cmake_content 51 | ) 52 | 53 | @unittest.skip("add dependency and fix test") 54 | def test_write_dependencies(self): 55 | """Write Dependencies""" 56 | 57 | with open(self.cur_dir + '/datatest/CMakeLists.txt') as cmake_lists_test: 58 | content_test = cmake_lists_test.read() 59 | self.assertTrue('''add_dependencies(${{PROJECT_NAME}} 60 | {0}g3log 61 | {0}zlib 62 | )'''.format(self.context.indent) in content_test) 63 | # self.assertTrue('link_directories(${DEPENDENCIES_DIR}/g3log)' in content_test) 64 | 65 | def test_link_dependencies(self): 66 | """Link Dependencies""" 67 | 68 | with open(self.cur_dir + '/datatest/CMakeLists.txt') as cmake_lists_test: 69 | self.assertTrue('''target_link_libraries(${{PROJECT_NAME}} PRIVATE 70 | {0}g3log 71 | {0}zlib 72 | )'''.format(self.context.indent) in cmake_lists_test.read()) 73 | -------------------------------------------------------------------------------- /test/test_data_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | import os 24 | import unittest 25 | import lxml 26 | import _io 27 | 28 | from cmake_converter.data_files import get_vcxproj_data, get_cmake_lists 29 | from cmake_converter.data_files import get_propertygroup, get_definitiongroup 30 | from cmake_converter.visual_studio.context import VSContext 31 | 32 | 33 | class TestDataFiles(unittest.TestCase): 34 | """ 35 | This file test 'data_files' functions 36 | """ 37 | 38 | cur_dir = os.path.dirname(os.path.realpath(__file__)) 39 | vs_project = '%s/datatest/foo.vcxproj' % cur_dir 40 | 41 | def test_get_vcxproj_data(self): 42 | """Get VS Project Data""" 43 | 44 | context = VSContext() 45 | under_test = get_vcxproj_data(context, self.vs_project) 46 | 47 | self.assertTrue('ns' in under_test) 48 | self.assertEqual( 49 | {'ns': 'http://schemas.microsoft.com/developer/msbuild/2003'}, 50 | under_test['ns'] 51 | ) 52 | self.assertTrue('tree' in under_test) 53 | self.assertIsInstance(under_test['tree'], lxml.etree._ElementTree) 54 | 55 | def test_get_propertygroup(self): 56 | """Get Property Group""" 57 | 58 | under_test = get_propertygroup(('Release', 'x64'), 'and @Label="Configuration"') 59 | 60 | self.assertTrue('PropertyGroup' in under_test) 61 | self.assertTrue('Release|x64' in under_test) 62 | 63 | def test_get_definitiongroup(self): 64 | """Get Definition Group""" 65 | 66 | under_test = get_definitiongroup(('Release', 'Win32')) 67 | 68 | self.assertTrue('ItemDefinitionGroup' in under_test) 69 | self.assertTrue('Release|Win32' in under_test) 70 | 71 | def test_get_cmakelists(self): 72 | """Get CMakeLists.txt""" 73 | 74 | context = VSContext() 75 | for under_test in get_cmake_lists(context, './'): 76 | self.assertTrue(under_test) 77 | self.assertIsInstance(under_test, _io.TextIOWrapper) 78 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/context.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Pavel Liavonau, liavonlida@gmail.com 6 | # 7 | # This file is part of (CMakeConverter). 8 | # 9 | # (CMakeConverter) is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU Affero General Public License as published by 11 | # the Free Software Foundation, either version 3 of the License, or 12 | # (at your option) any later version. 13 | # 14 | # (CMakeConverter) is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU Affero General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU Affero General Public License 20 | # along with (CMakeConverter). If not, see . 21 | 22 | """ 23 | Converter Context for visual studio solution 24 | ========================= 25 | """ 26 | 27 | from cmake_converter.context import Context 28 | 29 | from .vcxproj.dependencies import VCXDependencies 30 | from .vcxproj.flags import CPPFlags 31 | from .vcxproj.project_files import VCXProjectFiles 32 | from .vcxproj.project_variables import VCXProjectVariables 33 | from .vcxproj.utils import VCXUtils 34 | from .vcxproj.parser import VCXParser 35 | 36 | from .vfproj.dependencies import VFDependencies 37 | from .vfproj.flags import FortranFlags 38 | from .vfproj.project_files import VFProjectFiles 39 | from .vfproj.project_variables import VFProjectVariables 40 | from .vfproj.utils import VFUtils 41 | from .vfproj.parser import VFParser 42 | 43 | 44 | class VSContext(Context): 45 | """ 46 | Converter context for Visual Studio 47 | """ 48 | def __init__(self): 49 | Context.__init__(self) 50 | 51 | def get_project_initialization_dict(self): 52 | return { 53 | '.vcxproj': self.init_context_for_vcxproj, 54 | '.vfproj': self.init_context_for_vfproj 55 | } 56 | 57 | def init_context_for_vcxproj(self): 58 | """Makes initialization of helpers for C/C++ projects.""" 59 | self.variables = VCXProjectVariables() 60 | self.files = VCXProjectFiles() 61 | self.flags = CPPFlags() 62 | self.dependencies = VCXDependencies() 63 | self.utils = VCXUtils() 64 | self.parser = VCXParser() 65 | self.default_property_sheet = 'DEFAULT_CXX_PROPS' 66 | 67 | def init_context_for_vfproj(self): 68 | """Makes initialization of helpers for fortran projects.""" 69 | self.variables = VFProjectVariables() 70 | self.files = VFProjectFiles() 71 | self.flags = FortranFlags() 72 | self.dependencies = VFDependencies() 73 | self.utils = VFUtils() 74 | self.parser = VFParser() 75 | self.default_property_sheet = 'DEFAULT_Fortran_PROPS' 76 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/vfproj/project_variables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Module for defining CMake variables to be used by the Fortran project 25 | """ 26 | 27 | from cmake_converter.project_variables import ProjectVariables 28 | from cmake_converter.utils import message 29 | 30 | 31 | class VFProjectVariables(ProjectVariables): 32 | """ 33 | Class who defines all the CMake variables to be used by the Fortran project 34 | """ 35 | 36 | def set_output_dir(self, context, attr_name, output_dir, node): 37 | """ Set output directory for Fortran projects """ 38 | del attr_name, node 39 | 40 | self.set_output_dir_impl(context, output_dir) 41 | 42 | def set_output_file(self, context, flag_name, output_file, node): 43 | """ Set output file for Fortran projects """ 44 | del flag_name, node 45 | 46 | self.set_output_file_impl(context, output_file) 47 | 48 | def set_module_dir(self, context, flag_name, output_file, node): 49 | """ Set module directory for Fortran projects """ 50 | del flag_name, node 51 | 52 | self.set_path_and_name_from_node( 53 | context, 54 | 'Fortran module directory', 55 | output_file, 56 | 'Fortran_MODULE_DIRECTORY', 57 | 'Fortran_MODULE_NAME' # no support in CMake 58 | ) 59 | 60 | message( 61 | context, 62 | 'Fortran Module Directory will be ignored due lack of regex support at CMake\n' 63 | 'See walk-around at CMake/DefaultFortran.cmake', 'warn3' 64 | ) 65 | 66 | def set_import_library(self, context, flag_name, import_library, node): 67 | """ Set import library for Fortran projects """ 68 | del flag_name, node 69 | 70 | self.set_path_and_name_from_node( 71 | context, 72 | 'Import library', 73 | import_library, 74 | 'ARCHIVE_OUTPUT_DIRECTORY', 75 | 'ARCHIVE_OUTPUT_NAME' 76 | ) 77 | 78 | def set_program_database_file(self, context, flag_name, program_database_file, node): 79 | """ Set program database file for Fortran projects """ 80 | del flag_name, node 81 | self.set_path_and_name_from_node( 82 | context, 83 | 'Program database', 84 | program_database_file, 85 | 'PDB_OUTPUT_DIRECTORY', 86 | 'PDB_NAME' 87 | ) 88 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | import sys 24 | 25 | try: 26 | from setuptools import setup, find_packages 27 | except Exception: 28 | sys.exit("Error: missing python-setuptools library") 29 | 30 | try: 31 | python_version = sys.version_info 32 | except Exception: 33 | python_version = (1, 5) 34 | if python_version < (3, 6): 35 | sys.exit( 36 | "This application requires a minimum of Python 3.6 !" 37 | " Please update your Python version." 38 | ) 39 | 40 | from cmake_converter import __description__, __version__, __license__, __author__, __project_url__ 41 | from cmake_converter import __name__ as __pkg_name__ 42 | 43 | # Requirements 44 | install_requires = [ 45 | 'lxml', 46 | 'colorama', 47 | ] 48 | 49 | 50 | setup( 51 | name=__pkg_name__, 52 | version=__version__, 53 | 54 | license=__license__, 55 | 56 | # metadata for upload to PyPI 57 | author=__author__, 58 | author_email="liavonlida@gmail.com", 59 | keywords="cmake sln vcxproj vfproj visual cpp fortran CMakeLists", 60 | url=__project_url__, 61 | description=__description__, 62 | long_description=open('README.rst').read(), 63 | 64 | zip_safe=False, 65 | 66 | packages=find_packages(), 67 | python_requires='>=3.6', 68 | include_package_data=True, 69 | 70 | install_requires=install_requires, 71 | 72 | classifiers=[ 73 | 'Development Status :: 5 - Production/Stable', 74 | 'Environment :: Console', 75 | 'Intended Audience :: End Users/Desktop', 76 | 'Intended Audience :: Developers', 77 | 'Intended Audience :: System Administrators', 78 | 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 79 | 'Natural Language :: English', 80 | 'Operating System :: OS Independent', 81 | 'Programming Language :: Python :: 3', 82 | 'Programming Language :: Python :: 3.6', 83 | 'Programming Language :: Python :: 3.7', 84 | 'Programming Language :: Python :: 3.8', 85 | 'Programming Language :: Python :: 3.9', 86 | 'Topic :: Software Development :: Build Tools', 87 | 'Topic :: Software Development :: Code Generators', 88 | 'Topic :: Software Development :: Compilers', 89 | 'Topic :: Software Development :: Libraries' 90 | ], 91 | 92 | entry_points={ 93 | 'console_scripts': [ 94 | 'cmake-converter = cmake_converter.main:main' 95 | ], 96 | } 97 | 98 | ) 99 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/vcxproj/project_variables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Module that defines all the CMake variables to be used by the C/C++ project 25 | """ 26 | 27 | from cmake_converter.project_variables import ProjectVariables 28 | from cmake_converter.utils import message 29 | 30 | 31 | class VCXProjectVariables(ProjectVariables): 32 | """ 33 | Class that defines all the CMake variables to be used by the C/C++ project 34 | """ 35 | 36 | @staticmethod 37 | def set_root_namespace(context, node): 38 | """ Sets root namespace into context from node text""" 39 | context.root_namespace = node.text 40 | 41 | @staticmethod 42 | def set_project_name(context, node): 43 | """ Sets project name into context from node text""" 44 | context.project_name = node.text 45 | message( 46 | context, 47 | 'Project name is "{}"'.format(context.project_name), 48 | '' 49 | ) 50 | 51 | @staticmethod 52 | def set_keyword(context, node): 53 | """ Sets keyword of project type into context from node text """ 54 | context.settings[context.current_setting]['VS_GLOBAL_KEYWORD'] = [node.text] 55 | 56 | @staticmethod 57 | def set_windows_target_version(context, node): 58 | """ Sets windows target version(SDK version) into context from node text """ 59 | context.target_windows_version = node.text 60 | 61 | def set_output_dir(self, context, node): 62 | """ Sets output dir into context from node text """ 63 | self.set_output_dir_impl(context, node.text) 64 | 65 | def set_output_file(self, context, output_file_node): 66 | """ Sets output file into context from node text """ 67 | if output_file_node is not None: 68 | self.set_output_file_impl(context, output_file_node.text) 69 | 70 | def set_import_library(self, context, node): 71 | """ Sets import library into context from node text """ 72 | self.set_path_and_name_from_node( 73 | context, 74 | 'Import library', 75 | node.text, 76 | 'ARCHIVE_OUTPUT_DIRECTORY', 77 | 'ARCHIVE_OUTPUT_NAME' 78 | ) 79 | 80 | def set_program_database_file(self, context, node): 81 | """ Sets program database file into context from node text """ 82 | self.set_path_and_name_from_node( 83 | context, 84 | 'Program database', 85 | node.text, 86 | 'PDB_OUTPUT_DIRECTORY', 87 | 'PDB_NAME' 88 | ) 89 | -------------------------------------------------------------------------------- /test/datatest/sln/cpp.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2042 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foo", "..\foo.vcxproj", "{5A8227C8-F9A2-438D-9233-424CAB500B0F}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "external", "external", "{E17303BA-30AC-41FC-925A-500B1A77B092}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "g3log", "..\external\g3log.vcxproj", "{57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\external\zlib.vcxproj", "{A11C6B72-3902-43D3-ABD5-650012FB4029}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Win32 = Debug|Win32 17 | Debug|x64 = Debug|x64 18 | Release|Win32 = Release|Win32 19 | Release|x64 = Release|x64 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Debug|Win32.ActiveCfg = Debug|Win32 23 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Debug|Win32.Build.0 = Debug|Win32 24 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Debug|x64.ActiveCfg = Debug|x64 25 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Debug|x64.Build.0 = Debug|x64 26 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Release|Win32.ActiveCfg = Release|Win32 27 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Release|Win32.Build.0 = Release|Win32 28 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Release|x64.ActiveCfg = Release|x64 29 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Release|x64.Build.0 = Release|x64 30 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Debug|Win32.ActiveCfg = Debug|Win32 31 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Debug|Win32.Build.0 = Debug|Win32 32 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Debug|x64.ActiveCfg = Debug|x64 33 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Debug|x64.Build.0 = Debug|x64 34 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Release|Win32.ActiveCfg = Release|Win32 35 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Release|Win32.Build.0 = Release|Win32 36 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Release|x64.ActiveCfg = Release|x64 37 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Release|x64.Build.0 = Release|x64 38 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Debug|Win32.ActiveCfg = Debug|Win32 39 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Debug|Win32.Build.0 = Debug|Win32 40 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Debug|x64.ActiveCfg = Debug|x64 41 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Debug|x64.Build.0 = Debug|x64 42 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Release|Win32.ActiveCfg = Release|Win32 43 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Release|Win32.Build.0 = Release|Win32 44 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Release|x64.ActiveCfg = Release|x64 45 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Release|x64.Build.0 = Release|x64 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | GlobalSection(NestedProjects) = preSolution 51 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF} = {E17303BA-30AC-41FC-925A-500B1A77B092} 52 | {A11C6B72-3902-43D3-ABD5-650012FB4029} = {E17303BA-30AC-41FC-925A-500B1A77B092} 53 | EndGlobalSection 54 | GlobalSection(ExtensibilityGlobals) = postSolution 55 | SolutionGuid = {E4A87632-6225-4890-8F0E-02D19FDFA40C} 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/Default.cmake: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Command for variable_watch. This command issues error message, if a variable 3 | # is changed. If variable PROPERTY_READER_GUARD_DISABLED is TRUE nothing happens 4 | # variable_watch( property_reader_guard) 5 | ################################################################################ 6 | function(property_reader_guard VARIABLE ACCESS VALUE CURRENT_LIST_FILE STACK) 7 | if("${PROPERTY_READER_GUARD_DISABLED}") 8 | return() 9 | endif() 10 | 11 | if("${ACCESS}" STREQUAL "MODIFIED_ACCESS") 12 | message(FATAL_ERROR 13 | " Variable ${VARIABLE} is not supposed to be changed.\n" 14 | " It is used only for reading target property ${VARIABLE}.\n" 15 | " Use\n" 16 | " set_target_properties(\"\" PROPERTIES \"${VARIABLE}\" \"\")\n" 17 | " or\n" 18 | " set_target_properties(\"\" PROPERTIES \"${VARIABLE}_\" \"\")\n" 19 | " instead.\n") 20 | endif() 21 | endfunction() 22 | 23 | ################################################################################ 24 | # Create variable with generator expression that expands to value of 25 | # target property _. If property is empty or not set then property 26 | # is used instead. Variable has watcher property_reader_guard that 27 | # doesn't allow to edit it. 28 | # create_property_reader() 29 | # Input: 30 | # name - Name of watched property and output variable 31 | ################################################################################ 32 | function(create_property_reader NAME) 33 | set(PROPERTY_READER_GUARD_DISABLED TRUE) 34 | set(CONFIG_VALUE "$>>>") 35 | set(IS_CONFIG_VALUE_EMPTY "$") 36 | set(GENERAL_VALUE "$>") 37 | set("${NAME}" "$" PARENT_SCOPE) 38 | variable_watch("${NAME}" property_reader_guard) 39 | endfunction() 40 | 41 | ################################################################################ 42 | # Set property $_${PROPS_CONFIG_U} of ${PROPS_TARGET} to 43 | # set_config_specific_property( ) 44 | # Input: 45 | # name - Prefix of property name 46 | # value - New value 47 | ################################################################################ 48 | function(set_config_specific_property NAME VALUE) 49 | set_target_properties("${PROPS_TARGET}" PROPERTIES "${NAME}_${PROPS_CONFIG_U}" "${VALUE}") 50 | endfunction() 51 | 52 | ################################################################################ 53 | 54 | create_property_reader("TARGET_NAME") 55 | create_property_reader("OUTPUT_DIRECTORY") 56 | 57 | set_config_specific_property("TARGET_NAME" "${PROPS_TARGET}") 58 | set_config_specific_property("OUTPUT_NAME" "${TARGET_NAME}") 59 | set_config_specific_property("ARCHIVE_OUTPUT_NAME" "${TARGET_NAME}") 60 | set_config_specific_property("LIBRARY_OUTPUT_NAME" "${TARGET_NAME}") 61 | set_config_specific_property("RUNTIME_OUTPUT_NAME" "${TARGET_NAME}") 62 | 63 | set_config_specific_property("ARCHIVE_OUTPUT_DIRECTORY" "${OUTPUT_DIRECTORY}") 64 | set_config_specific_property("LIBRARY_OUTPUT_DIRECTORY" "${OUTPUT_DIRECTORY}") 65 | set_config_specific_property("RUNTIME_OUTPUT_DIRECTORY" "${OUTPUT_DIRECTORY}") -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | CMake Converter 2 | =============== 3 | 4 | .. image:: https://travis-ci.org/pavelliavonau/cmakeconverter.svg?branch=develop 5 | :target: https://travis-ci.org/pavelliavonau/cmakeconverter 6 | .. image:: https://landscape.io/github/pavelliavonau/cmakeconverter/develop/landscape.svg?style=flat 7 | :target: https://landscape.io/github/pavelliavonau/cmakeconverter/develop 8 | :alt: Code Health 9 | .. image:: https://coveralls.io/repos/github/pavelliavonau/cmakeconverter/badge.svg?branch=develop 10 | :target: https://coveralls.io/github/pavelliavonau/cmakeconverter?branch=develop 11 | .. image:: http://readthedocs.org/projects/cmakeconverter/badge/?version=develop 12 | :target: http://cmakeconverter.readthedocs.io/en/develop/?badge=develop 13 | :alt: Documentation Status 14 | .. image:: https://badge.fury.io/py/cmake-converter.svg 15 | :target: https://badge.fury.io/py/cmake-converter 16 | :alt: Most recent PyPi version 17 | .. image:: https://img.shields.io/pypi/pyversions/cmake_converter.svg 18 | :target: https://pypi.org/project/cmake_converter/ 19 | :alt: Supported Python versions 20 | .. image:: https://img.shields.io/badge/License-AGPL%20v3-blue.svg 21 | :target: http://www.gnu.org/licenses/agpl-3.0 22 | :alt: License AGPL v3 23 | .. image:: https://img.shields.io/badge/Donate-PayPal-green.svg 24 | :target: https://www.paypal.me/pavelliavonau 25 | 26 | Introduction 27 | ------------ 28 | 29 | This project aims to facilitate the conversion of Visual Studio solution to CMake projects. 30 | The goal is to give to a Python script, a **\*.sln** file, and output a set of **CMakeLists.txt** that may be used for generating visual studio solution backward as perfect as possible. Project is useful for porting VS projects into CMake build system. 31 | 32 | **Note :** Actually, it's **only works** with ``C/C++`` (\*.vcxproj) and ``Fortran`` (\*.vfproj) projects. 33 | 34 | Install & Run 35 | ------------- 36 | 37 | Install package from PyPI 38 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 39 | 40 | Install last stable release of cmake-converter:: 41 | 42 | pip install cmake-converter 43 | 44 | **Note :** **If you found an issue** in the package installed from pip, please, **do not create github issue at once** and check for pre-release version (pip -pre) or last source from develop first. It might be has fixed already and ready to release. 45 | 46 | Install package from source code 47 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 48 | 49 | Simply clone or download the repository and type the following command to install it:: 50 | 51 | # Inside repository folder. 52 | pip install . 53 | 54 | Run 55 | ~~~ 56 | 57 | After install library, just run the script as below. Your ``*.sln`` file is of course required:: 58 | 59 | cmake-converter -s 60 | 61 | **Note :** If you satisfied with conversion, give a star to the project and consider to donate, please. 62 | 63 | Documentation 64 | ------------- 65 | 66 | Documentation for CMake Converter is available on `Read The Docs `_. 67 | 68 | Bugs, issues and contributing 69 | ----------------------------- 70 | 71 | Contributions to this project are welcome and encouraged ... 72 | Issues in the project repository are the common way to raise an information. 73 | 74 | **Note:** if you have an issue, please provide me if possible the visual studio project involved. 75 | 76 | Donations 77 | -------------------------- 78 | 79 | If you appreciate my efforts related to this project, give me a gift. I'll be glad to get some money working for free ;) 80 | To make a donation - please press the button below. 81 | 82 | .. image:: https://raw.githubusercontent.com/stefan-niedermann/paypal-donate-button/master/paypal-donate-button.png 83 | :target: https://www.paypal.me/pavelliavonau -------------------------------------------------------------------------------- /test/test_data_converter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | import os 24 | import unittest 25 | 26 | from cmake_converter.data_converter import DataConverter 27 | from cmake_converter.visual_studio.context import VSContext 28 | 29 | 30 | class TestDataConverter(unittest.TestCase): 31 | """ 32 | This file test methods of DataConverter class. 33 | """ 34 | 35 | cur_dir = os.path.dirname(os.path.realpath(__file__)) 36 | vs_project = '%s/datatest/foo.vcxproj' % cur_dir 37 | 38 | def test_context_init(self): 39 | """Data Converter Init Files""" 40 | 41 | under_test = VSContext() 42 | 43 | self.assertEqual(under_test.cmake, '') 44 | self.assertEqual(under_test.xml_data, {}) 45 | 46 | under_test.init(self.vs_project, self.cur_dir) 47 | 48 | self.assertNotEqual(under_test.cmake, '') 49 | # self.assertIsNotNone(under_test.vcxproj) 50 | 51 | # self.assertTrue('ns' in under_test.vcxproj) 52 | # self.assertTrue('tree' in under_test.vcxproj) 53 | 54 | def test_create_data(self): 55 | """Data Converter Create Data""" 56 | 57 | # FIXME: No such file or directory: 'CMakeLists.txt' 58 | return 59 | 60 | under_test = DataConverter() 61 | 62 | context = VSContext() 63 | context.init(self.vs_project, self.cur_dir) 64 | 65 | old_cmake = open('CMakeLists.txt', 'r') 66 | 67 | under_test.convert(context) 68 | 69 | new_cmake = open('CMakeLists.txt', 'r') 70 | 71 | # Assert content is not the same after 72 | self.assertEqual(old_cmake.read(), new_cmake.read()) 73 | 74 | old_cmake.close() 75 | new_cmake.close() 76 | 77 | def test_receive_wrong_cmake_path(self): 78 | """Wrong CMake Path Write in Current Directory""" 79 | 80 | under_test = VSContext() 81 | under_test.init(self.vs_project, '/wrong/path/to/cmake') 82 | 83 | # CMakeLists.txt is created in the current directory 84 | self.assertEqual('CMakeLists.txt', under_test.cmake) 85 | 86 | ''' #TODO: lost feature? 87 | def test_inclusion_of_cmake_is_written(self): 88 | """Inclusion of ".cmake" File is Written""" 89 | 90 | data_test = { 91 | 'cmake': './', 92 | 'cmakeoutput': '', 93 | 'vcxproj': self.vs_project, 94 | 'project': self.vs_project, 95 | 'include': '../../test.txt', 96 | 'includecmake': '../../test.cmake', 97 | 'additional': '', 98 | } 99 | under_test = DataConverter(data_test) 100 | under_test.init_files(self.vs_project, '.') 101 | under_test.data['cmake'] = get_cmake_lists(context, './') 102 | 103 | under_test.create_data() 104 | under_test.close_cmake_file() 105 | 106 | cmakelists_test = open('CMakeLists.txt') 107 | 108 | content_test = cmakelists_test.read() 109 | 110 | # Includes are added 111 | self.assertTrue('Include files and directories' in content_test) 112 | self.assertTrue('../../test.cmake' in content_test) 113 | 114 | # File "test.txt" is not added because it does not exist 115 | self.assertTrue('../../test.txt' not in content_test) 116 | 117 | cmakelists_test.close() 118 | ''' 119 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/vfproj/project_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Module for project files properties for Fortran projects 25 | """ 26 | 27 | import re 28 | import os 29 | 30 | from cmake_converter.project_files import ProjectFiles 31 | from cmake_converter.utils import message 32 | 33 | 34 | class VFProjectFiles(ProjectFiles): 35 | """ 36 | Class project files properties for Fortran projects 37 | """ 38 | 39 | def include_directive_case_check(self, context, file_path_name, file_lists_for_include_paths): 40 | """ 41 | Check for absence of files at include directives (case sensitive) 42 | 43 | :param context: 44 | :param file_path_name: 45 | :param file_lists_for_include_paths: 46 | :return: 47 | """ 48 | includes_re = re.compile( 49 | r'include \'(.*)\'', re.IGNORECASE 50 | ) 51 | file_abs_path = os.path.join(os.path.dirname(context.vcxproj_path), file_path_name) 52 | 53 | file_text = '' 54 | with open(file_abs_path, 'r', errors='replace', encoding='utf-8') as file: 55 | file_text = file.read() 56 | includes = includes_re.findall(file_text) 57 | 58 | checked_includes = set() 59 | for include_name_in_file in includes: 60 | if include_name_in_file in checked_includes: 61 | continue 62 | checked_includes.add(include_name_in_file) 63 | 64 | include_file_path, include_file_name = os.path.split(include_name_in_file) 65 | 66 | # add current file path to search list helper 67 | current_file_path = os.path.normpath(os.path.dirname(file_abs_path)) 68 | if os.path.exists(current_file_path): 69 | file_lists_for_include_paths[current_file_path] = set(os.listdir(current_file_path)) 70 | 71 | if not self.search_file_in_paths( 72 | file_lists_for_include_paths, 73 | include_file_path, 74 | include_file_name): 75 | message(context, 'include {} from file {} not found' 76 | .format(include_name_in_file, file_path_name), 'error') 77 | 78 | @staticmethod 79 | def search_file_in_paths(file_lists_for_include_paths, include_file_path, include_file_name): 80 | """ 81 | Search of file at filesystem(cached) case sensitive 82 | 83 | :param file_lists_for_include_paths: 84 | :param include_file_path: 85 | :param include_file_name: 86 | :return: 87 | """ 88 | found = False 89 | file_lists_for_includes_with_paths = {} 90 | for include_path in file_lists_for_include_paths: 91 | joined_include_path = os.path.normpath(os.path.join(include_path, include_file_path)) 92 | files = {} 93 | if joined_include_path in file_lists_for_include_paths: 94 | files = file_lists_for_include_paths[joined_include_path] 95 | else: 96 | if os.path.exists(joined_include_path): 97 | files = set(os.listdir(joined_include_path)) 98 | file_lists_for_includes_with_paths[joined_include_path] = files 99 | 100 | if include_file_name in files: 101 | found = True 102 | break 103 | 104 | file_lists_for_include_paths.update(file_lists_for_includes_with_paths) 105 | 106 | return found 107 | -------------------------------------------------------------------------------- /cmake_converter/dependencies.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Dependencies 25 | ============ 26 | Manage directories and libraries of project dependencies 27 | """ 28 | 29 | import ntpath 30 | import os 31 | import re 32 | 33 | from cmake_converter.data_files import get_vcxproj_data 34 | from cmake_converter.utils import get_global_project_name_from_vcxproj_file, normalize_path, message 35 | from cmake_converter.utils import replace_vs_vars_with_cmake_vars, resolve_path_variables_of_vs 36 | 37 | 38 | class Dependencies: 39 | """ 40 | Class who find and write dependencies of project, additional directories... 41 | """ 42 | 43 | @staticmethod 44 | def set_additional_include_directories(aid_text, setting, context): 45 | """ 46 | Return additional include directories of given context 47 | 48 | :param aid_text: path to sources 49 | :type aid_text: str 50 | :param setting: current setting (Debug|x64, Release|Win32,...) 51 | :type setting: str 52 | :param context: current context 53 | :type context: Context 54 | :return: include directories of context, separated by semicolons 55 | :rtype: str 56 | """ 57 | 58 | if not aid_text: 59 | return 60 | 61 | working_path = os.path.dirname(context.vcxproj_path) 62 | inc_dir = resolve_path_variables_of_vs(context, aid_text) 63 | inc_dir = inc_dir.replace('%(AdditionalIncludeDirectories)', '') 64 | inc_dirs = context.settings[setting]['inc_dirs'] 65 | dirs_raw = [] 66 | for i in inc_dir.split(';'): 67 | if i: 68 | dirs_raw.append(i) 69 | i = normalize_path(context, working_path, i) 70 | i = replace_vs_vars_with_cmake_vars(context, i) 71 | inc_dirs.append(i) 72 | 73 | context.settings[setting]['inc_dirs_list'].extend(dirs_raw) 74 | 75 | if inc_dirs: 76 | message( 77 | context, 78 | 'Include Directories : {}'.format(context.settings[setting]['inc_dirs']), 79 | '') 80 | 81 | @staticmethod 82 | def set_target_additional_dependencies_impl(context, dependencies_text, splitter): 83 | """ Implementation of Handler for additional link dependencies """ 84 | dependencies_text = dependencies_text.replace('%(AdditionalDependencies)', '') 85 | add_libs = [] 86 | for d in re.split(splitter, dependencies_text): 87 | if d: 88 | d = re.sub(r'\.lib$', '', d, 0, re.IGNORECASE) # strip lib extension 89 | add_libs.append(d) 90 | 91 | if add_libs: 92 | context.add_lib_deps = True 93 | message(context, 'Additional Dependencies : {}'.format(add_libs), '') 94 | context.settings[context.current_setting]['add_lib_deps'] = add_libs 95 | 96 | @staticmethod 97 | def get_dependency_target_name(context, vs_project): 98 | """ 99 | Return dependency target name 100 | 101 | :param context: the context of converter 102 | :type context: Context 103 | :param vs_project: path to ".vcxproj" file 104 | :type vs_project: str 105 | :return: target name 106 | :rtype: str 107 | """ 108 | 109 | vcxproj = get_vcxproj_data(context, vs_project) 110 | project_name = get_global_project_name_from_vcxproj_file(vcxproj) 111 | 112 | if project_name: 113 | return project_name 114 | 115 | return os.path.splitext(ntpath.basename(vs_project))[0] 116 | -------------------------------------------------------------------------------- /docs/cmake.rst: -------------------------------------------------------------------------------- 1 | .. _cmake: 2 | 3 | Generated CMakeLists.txt 4 | ************************ 5 | 6 | All **CMakeLists.txt** generated by cmake-converter follow the same hierarchy. 7 | If you converted a solution, each converted directory with \*proj file will have its own file. 8 | 9 | In order to facilitate their understanding, the generated files are organized by "section". Here is a description for each of them. 10 | Actually each section at generated scripts is separated with comment and can be read well. 11 | 12 | Root of CMake tree 13 | ================== 14 | 15 | After conversion the root of CMake tree appears beside \*.sln file. 16 | So, give the path of the root CMakeLists.txt to cmake to parse all converted tree. 17 | Root CMakeLists.txt contains info about:: 18 | 19 | 1. Architectures used in solution. 20 | 2. Solution configutation names. 21 | 3. Windows SDK version used. 22 | 4. Sets cmake minimum required version. 23 | 5. Includes optional GlobalSettingsInclude.cmake 24 | 6. Adds all converted subdirectories with projects. 25 | 26 | Top of file (project) 27 | ===================== 28 | 29 | Creating of corresponding Visual Studio project with used languages. 30 | 31 | Files & Targets 32 | =============== 33 | 34 | Files (source groups) 35 | --------------------- 36 | 37 | Converter will collect all your source files and add them to the corresponding target. 38 | The files will be added according source groups and sorted alphabetically. 39 | 40 | **IMPORTANT:** names of source groups must be without special symbols (only CMake like variable). Spaces are accepted. 41 | 42 | Library & Executable (target) 43 | ----------------------------- 44 | 45 | After script get all information, he create your library (`STATIC` or `SHARED`) or your executable. 46 | Also here may be used add_precompiled_header if PCH is turned on. 47 | 48 | Property files (\*.props) 49 | ------------------------- 50 | 51 | Converter does not support translation of property. It addes links to correspondent files at the same location. 52 | Example: 53 | if we have following link at source xml: 54 | 55 | f1/f2/my-settings.props 56 | 57 | You'll get usage of similar cmake file that should be created manually: 58 | 59 | use_props(${PROJECT_NAME} "${CMAKE_CONFIGURATION_TYPES}" "f1/f2/my-settings.cmake") 60 | 61 | In case of absence of cmake file CMake will throw warning: 62 | 63 | Corresponding cmake file from props doesn't exist 64 | 65 | Include directories 66 | =================== 67 | 68 | Adds include directories from corresponding visual studio project. 69 | Includes are PUBLIC by default. 70 | But you may use --private-include-directories to make them private and make your solution smarter. 71 | 72 | Compile definitions 73 | =================== 74 | 75 | Adds compile definitions from corresponding visual studio project. 76 | 77 | Compile and link options 78 | ======================== 79 | 80 | The biggest part of the work done by CMake Converter. CMake-converter will add flags for each ``$``. 81 | Only MSVC and ifort compilers are supported. Flags applied with target_compile_options and target_link_options. 82 | 83 | Linux 84 | ----- 85 | 86 | On Linux only translation of ifort options is supported. 87 | 88 | Windows 89 | ------- 90 | 91 | MSVC and ifort options are supported. 92 | 93 | Dependencies 94 | ============ 95 | 96 | Dependencies are binaries you have set in "Additional Dependencies" of your ***proj** project, like shared or static libraries or references to other solution projects. 97 | ``add_dependencies`` command contains corresponding references. 98 | ``target_link_libraries`` command contains references that need to link and other external dependencies. 99 | ``target_link_directories`` may be used here as well. 100 | 101 | Also cmake converter tries to read info about used NuGet packages and makes stubs for using it with ``use_package`` function. 102 | 103 | Use CMake 104 | ********* 105 | 106 | CMake Converter try to take as much information as possible from your ***proj** file. 107 | However, it's recommended to read and test the generated **CMakeLists.txt** before using it in production ! 108 | 109 | Once CMake Converter has generated a **CMakeLists.txt** file, to compile with CMake, type the following commands:: 110 | 111 | # Go to CMake tree root (not necessary, may be relative): 112 | cd path/to/Root/of/CMake/tree 113 | # Generate the "Makefile" 114 | cmake -S . -B build 115 | # Launch compilation 116 | cmake --build build 117 | 118 | You can also provide a specific **Generator** with ``-G ""``. Please refer to `CMake Generator Documentation `_. 119 | 120 | You can provide the build type by add ``-DCMAKE_BUILD_TYPE=``. 121 | 122 | CMake provides a lot of other options that you can discover in their official documentation. 123 | 124 | -------------------------------------------------------------------------------- /test/test_project_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | import os 24 | import unittest 25 | 26 | from cmake_converter.visual_studio.context import VSContext 27 | from cmake_converter.visual_studio.solution import VSSolutionConverter 28 | from cmake_converter.project_files import ProjectFiles 29 | from cmake_converter.data_files import get_cmake_lists 30 | 31 | 32 | class TestProjectFiles(unittest.TestCase): 33 | """ 34 | This file test methods of ProjectFiles class. 35 | """ 36 | 37 | context = VSContext() 38 | cur_dir = os.path.dirname(os.path.realpath(__file__)) 39 | 40 | def setUp(self): 41 | self.context.verbose = False 42 | solution_file = '{}/datatest/sln/cpp.sln'.format(self.cur_dir) 43 | converter = VSSolutionConverter() 44 | converter.convert_solution(self.context, os.path.abspath(solution_file)) 45 | 46 | @unittest.skip("how to test sources from project context?") 47 | def test_collects_source_files(self): 48 | """Collects Source Files""" 49 | 50 | self.assertNotEqual(len(self.context.sources), 0) 51 | self.assertEqual(len(self.context.headers), 0) 52 | 53 | def test_write_source_files(self): 54 | """Write Source Files""" 55 | 56 | with open('{}/datatest/CMakeLists.txt'.format(self.cur_dir)) as cmake_lists_test: 57 | content_test = cmake_lists_test.read() 58 | self.assertTrue('source_group("Sources" FILES ${Sources})' in content_test) 59 | 60 | @unittest.skip("repair test additional code") 61 | def test_add_additional_code(self): 62 | """Add Additional CMake Code""" 63 | 64 | # When file is empty, nothing is added 65 | self.data_test['cmake'] = get_cmake_lists(context, self.cur_dir) 66 | under_test = ProjectFiles(self.data_test) 67 | 68 | under_test.add_additional_code(context, '') 69 | 70 | under_test.cmake.close() 71 | 72 | cmakelists_test = open('%s/CMakeLists.txt' % self.cur_dir) 73 | content_test = cmakelists_test.read() 74 | 75 | self.assertEqual('', content_test) 76 | cmakelists_test.close() 77 | 78 | # When file exist, code is added 79 | under_test.cmake = get_cmake_lists(context, self.cur_dir) 80 | under_test.add_additional_code(context, '%s/datatest/additional_code_test.cmake' % self.cur_dir) 81 | 82 | under_test.cmake.close() 83 | 84 | cmakelists_test = open('%s/CMakeLists.txt' % self.cur_dir) 85 | content_test = cmakelists_test.read() 86 | 87 | self.assertTrue('set(ADD_CODE code)' in content_test) 88 | 89 | cmakelists_test.close() 90 | 91 | # When file does not exist, nothing is added 92 | under_test.cmake = get_cmake_lists(context, self.cur_dir) 93 | under_test.add_additional_code(context, 'nofile/additional_code_test.cmake') 94 | 95 | under_test.cmake.close() 96 | 97 | cmakelists_add_test = open('%s/CMakeLists.txt' % self.cur_dir) 98 | content_add_test = cmakelists_add_test.read() 99 | 100 | self.assertEqual('', content_add_test) 101 | 102 | cmakelists_test.close() 103 | 104 | def test_add_artefacts(self): 105 | """Add Artefact Target""" 106 | 107 | with open('{}/datatest/CMakeLists.txt'.format(self.cur_dir)) as cmake_lists_test: 108 | content_test = cmake_lists_test.read() 109 | self.assertTrue('add_executable(${PROJECT_NAME} ${ALL_FILES})' in content_test) 110 | 111 | @unittest.skip("include_cmake deleted") 112 | def test_add_include_cmake(self): 113 | """Add Include CMake File""" 114 | 115 | self.data_test['cmake'] = get_cmake_lists(context, self.cur_dir) 116 | under_test = ProjectFiles(self.data_test) 117 | 118 | under_test.add_include_cmake('path/to/file.cmake') 119 | self.data_test['cmake'].close() 120 | 121 | cmakelists_test = open('%s/CMakeLists.txt' % self.cur_dir) 122 | content_test = cmakelists_test.read() 123 | 124 | self.assertTrue('include("path/to/file.cmake")' in content_test) 125 | -------------------------------------------------------------------------------- /cmake_converter/parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Pavel Liavonau, liavonlida@gmail.com 6 | # Matthieu Estrada, ttamalfor@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Module of Basic logic of parsers for Visual Solution projects 25 | """ 26 | 27 | import re 28 | 29 | from cmake_converter.utils import message 30 | 31 | 32 | class StopParseException(Exception): 33 | """ Just another well-named exception class for interrupting parsing """ 34 | 35 | 36 | class Parser: 37 | """ 38 | Basic class of parsers for Visual Solution projects 39 | """ 40 | def __init__(self): 41 | self.reset_setting_after_nodes = set() 42 | 43 | @staticmethod 44 | def parse(context): 45 | """ Basic implementation main parser entry point """ 46 | message(context, 'Parser is not implemented yet!', 'error') 47 | 48 | @staticmethod 49 | def do_nothing_node_stub(context, node): 50 | """ Just stub for do nothing on handling node attempt """ 51 | 52 | @staticmethod 53 | def do_nothing_attr_stub(context, attr_name, param, node): 54 | """ Just stub for do nothing on handling attribute attempt """ 55 | 56 | def get_node_handlers_dict(self, context): 57 | """ Basic implementation of getting node handlers dict """ 58 | raise NotImplementedError('You need to define a get_node_handlers_dict method!') 59 | 60 | def get_attribute_handlers_dict(self, context): 61 | """ Basic implementation of getting attribute handlers dict """ 62 | raise NotImplementedError('You need to define a get_attribute_handlers_dict method!') 63 | 64 | def reset_current_setting_after_parsing_node(self, node): 65 | """ Remember node after parsing that current setting must be reset """ 66 | self.reset_setting_after_nodes.add(node) 67 | 68 | @staticmethod 69 | def strip_namespace(tag): 70 | """ Removes namespace from xml tag """ 71 | return re.sub(r'{.*\}', '', tag) 72 | 73 | def _parse_nodes(self, context, parent): 74 | for child_node in parent: 75 | if not isinstance(child_node.tag, str): 76 | continue 77 | child_node_tag = Parser.strip_namespace(child_node.tag) 78 | 79 | message( 80 | context, 81 | 'Parsing... line {} node {} attrib {}'.format( 82 | child_node.sourceline, 83 | child_node_tag, 84 | child_node.attrib 85 | ), 86 | '' 87 | ) 88 | 89 | context.current_node = child_node 90 | 91 | try: 92 | self._parse_attributes(context, child_node) 93 | except StopParseException: 94 | context.current_node = parent 95 | continue 96 | 97 | node_handlers = self.get_node_handlers_dict(context) 98 | if child_node_tag in node_handlers: 99 | if child_node.text is not None: 100 | child_node.text = child_node.text.strip() 101 | node_handlers[child_node_tag](context, child_node) 102 | else: 103 | message(context, 'No handler for <{}> node.'.format(child_node_tag), 'warn3') 104 | 105 | if child_node in self.reset_setting_after_nodes: 106 | context.current_setting = (None, None) 107 | self.reset_setting_after_nodes.remove(child_node) 108 | 109 | context.current_node = parent 110 | 111 | def _parse_attributes(self, context, node): 112 | for attr in node.attrib: 113 | node_tag = Parser.strip_namespace(node.tag) 114 | node_key = '{}_{}'.format(node_tag, attr) 115 | attributes_handlers = self.get_attribute_handlers_dict(context) 116 | if node_key in attributes_handlers: # node specified handler 117 | attributes_handlers[node_key](context, node_key, node.get(attr), node) 118 | elif attr in attributes_handlers: # common attribute handler 119 | attributes_handlers[attr](context, attr, node.get(attr), node) 120 | else: 121 | message( 122 | context, 123 | 'No handler for "{}" attribute of <{}> node.'.format(attr, node_tag), 124 | 'warn3' 125 | ) 126 | -------------------------------------------------------------------------------- /test/datatest/sln/cpp_and_fortran.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2042 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foo", "..\foo.vcxproj", "{5A8227C8-F9A2-438D-9233-424CAB500B0F}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "external", "external", "{E17303BA-30AC-41FC-925A-500B1A77B092}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "g3log", "..\external\g3log.vcxproj", "{57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\external\zlib.vcxproj", "{A11C6B72-3902-43D3-ABD5-650012FB4029}" 13 | EndProject 14 | Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = "bar", "bar.vfproj", "{21E6B56B-E42A-4213-8852-E591ACED5D27}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Win32 = Debug|Win32 19 | Debug|x64 = Debug|x64 20 | Debug|x86 = Debug|x86 21 | Release|Win32 = Release|Win32 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Debug|Win32.ActiveCfg = Debug|Win32 27 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Debug|Win32.Build.0 = Debug|Win32 28 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Debug|x64.ActiveCfg = Debug|x64 29 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Debug|x64.Build.0 = Debug|x64 30 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Debug|x86.ActiveCfg = Debug|Win32 31 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Debug|x86.Build.0 = Debug|Win32 32 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Release|Win32.ActiveCfg = Release|Win32 33 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Release|Win32.Build.0 = Release|Win32 34 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Release|x64.ActiveCfg = Release|x64 35 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Release|x64.Build.0 = Release|x64 36 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Release|x86.ActiveCfg = Release|Win32 37 | {5A8227C8-F9A2-438D-9233-424CAB500B0F}.Release|x86.Build.0 = Release|Win32 38 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Debug|Win32.ActiveCfg = Debug|Win32 39 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Debug|Win32.Build.0 = Debug|Win32 40 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Debug|x64.ActiveCfg = Debug|x64 41 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Debug|x64.Build.0 = Debug|x64 42 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Debug|x86.ActiveCfg = Debug|Win32 43 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Debug|x86.Build.0 = Debug|Win32 44 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Release|Win32.ActiveCfg = Release|Win32 45 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Release|Win32.Build.0 = Release|Win32 46 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Release|x64.ActiveCfg = Release|x64 47 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Release|x64.Build.0 = Release|x64 48 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Release|x86.ActiveCfg = Release|Win32 49 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF}.Release|x86.Build.0 = Release|Win32 50 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Debug|Win32.ActiveCfg = Debug|Win32 51 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Debug|Win32.Build.0 = Debug|Win32 52 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Debug|x64.ActiveCfg = Debug|x64 53 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Debug|x64.Build.0 = Debug|x64 54 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Debug|x86.ActiveCfg = Debug|Win32 55 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Debug|x86.Build.0 = Debug|Win32 56 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Release|Win32.ActiveCfg = Release|Win32 57 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Release|Win32.Build.0 = Release|Win32 58 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Release|x64.ActiveCfg = Release|x64 59 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Release|x64.Build.0 = Release|x64 60 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Release|x86.ActiveCfg = Release|Win32 61 | {A11C6B72-3902-43D3-ABD5-650012FB4029}.Release|x86.Build.0 = Release|Win32 62 | {21E6B56B-E42A-4213-8852-E591ACED5D27}.Debug|Win32.ActiveCfg = Debug|Win32 63 | {21E6B56B-E42A-4213-8852-E591ACED5D27}.Debug|Win32.Build.0 = Debug|Win32 64 | {21E6B56B-E42A-4213-8852-E591ACED5D27}.Debug|x64.ActiveCfg = Debug|x64 65 | {21E6B56B-E42A-4213-8852-E591ACED5D27}.Debug|x64.Build.0 = Debug|x64 66 | {21E6B56B-E42A-4213-8852-E591ACED5D27}.Debug|x86.ActiveCfg = Debug|x64 67 | {21E6B56B-E42A-4213-8852-E591ACED5D27}.Release|Win32.ActiveCfg = Release|Win32 68 | {21E6B56B-E42A-4213-8852-E591ACED5D27}.Release|Win32.Build.0 = Release|Win32 69 | {21E6B56B-E42A-4213-8852-E591ACED5D27}.Release|x64.ActiveCfg = Release|x64 70 | {21E6B56B-E42A-4213-8852-E591ACED5D27}.Release|x64.Build.0 = Release|x64 71 | {21E6B56B-E42A-4213-8852-E591ACED5D27}.Release|x86.ActiveCfg = Release|x64 72 | EndGlobalSection 73 | GlobalSection(SolutionProperties) = preSolution 74 | HideSolutionNode = FALSE 75 | EndGlobalSection 76 | GlobalSection(NestedProjects) = preSolution 77 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF} = {E17303BA-30AC-41FC-925A-500B1A77B092} 78 | {A11C6B72-3902-43D3-ABD5-650012FB4029} = {E17303BA-30AC-41FC-925A-500B1A77B092} 79 | EndGlobalSection 80 | GlobalSection(ExtensibilityGlobals) = postSolution 81 | SolutionGuid = {E4A87632-6225-4890-8F0E-02D19FDFA40C} 82 | EndGlobalSection 83 | EndGlobal 84 | -------------------------------------------------------------------------------- /cmake_converter/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Main 25 | ==== 26 | Manage script arguments and launch 27 | """ 28 | 29 | import argparse 30 | import os 31 | 32 | from cmake_converter.visual_studio.context import VSContext 33 | from cmake_converter.visual_studio.solution import VSSolutionConverter 34 | from cmake_converter.utils import message 35 | 36 | 37 | def main(): # pragma: no cover 38 | """ 39 | Define arguments and message to DataConverter() 40 | 41 | """ 42 | 43 | usage = "cmake-converter -s " \ 44 | "[ -h | -s | -p | -i | -d | -v | -w | -j | -a | -pi | -ias ]" 45 | parser = argparse.ArgumentParser( 46 | usage=usage, 47 | description='Converts Visual Studio projects in solution (*.sln) to CMakeLists.txt tree' 48 | ) 49 | parser.add_argument( 50 | '-s', '--solution', 51 | help='[required] valid solution file. i.e.: ../../my.sln', 52 | required=True, 53 | dest='solution' 54 | ) 55 | parser.add_argument( 56 | '-p', '--projects-filter', 57 | help='python regexp to filter that projects should be converted from the given solution', 58 | dest='projects_regexp' 59 | ) 60 | parser.add_argument( 61 | '-i', '--indent', 62 | help='indentation for formatting of out CMakeLists.txt', 63 | dest='indent' 64 | ) 65 | parser.add_argument( 66 | '-d', '--dry-run', 67 | help='run converter without touching files.', 68 | dest='dry', 69 | action='store_true' 70 | ) 71 | parser.add_argument( 72 | '-v', '--verbose-mode', 73 | help='run converter with more messages in log.', 74 | dest='verbose', 75 | action='store_true' 76 | ) 77 | parser.add_argument( 78 | '-w', '--warning-level', 79 | help='run converter with given verbosity of warnings([1..4] default=2).', 80 | dest='warn', 81 | ) 82 | parser.add_argument( 83 | '-j', '--jobs', 84 | help='run converter using given number of processes.', 85 | dest='jobs', 86 | ) 87 | parser.add_argument( 88 | '-a', '--additional', 89 | help='[experimental] import cmake code from file.cmake to your final CMakeLists.txt', 90 | dest='additional' 91 | ) 92 | parser.add_argument( 93 | '-pi', '--private-include-directories', 94 | help='use PRIVATE specifier for target_include_directories', 95 | dest='private_includes', 96 | default=False, 97 | action='store_true' 98 | ) 99 | parser.add_argument( 100 | '-ias', '--ignore-absent-sources', 101 | help='do not add absent source files to CMakeLists.txt', 102 | dest='ignore_absent_sources', 103 | default=False, 104 | action='store_true' 105 | ) 106 | 107 | args = parser.parse_args() 108 | 109 | project_context = VSContext() 110 | # Prepare context 111 | project_context.additional_code = args.additional 112 | 113 | if args.projects_regexp: 114 | project_context.projects_regexp = args.projects_regexp 115 | 116 | if args.indent: 117 | project_context.indent = args.indent 118 | 119 | if args.dry: 120 | project_context.dry = True 121 | message(project_context, 'Converter runs in dry mode', 'done') 122 | 123 | if args.verbose: 124 | project_context.verbose = True 125 | message(project_context, 'Converter runs in verbose mode', 'done') 126 | 127 | if args.jobs: 128 | project_context.jobs = int(args.jobs) 129 | message(project_context, 'processes count = {}'. format(project_context.jobs), 'done') 130 | 131 | if args.warn: 132 | project_context.warn_level = int(args.warn) 133 | message(project_context, 'warnings level = {}'. format(project_context.warn_level), 'done') 134 | 135 | if args.private_includes: 136 | message(project_context, 'include directories will be PRIVATE', 'done') 137 | project_context.private_include_directories = True 138 | 139 | if args.ignore_absent_sources: 140 | message(project_context, 'absent source files will be ignored', 'done') 141 | project_context.ignore_absent_sources = True 142 | 143 | converter = VSSolutionConverter() 144 | converter.convert_solution(project_context, os.path.abspath(args.solution)) 145 | 146 | 147 | if __name__ == "__main__": # pragma: no cover 148 | main() 149 | -------------------------------------------------------------------------------- /cmake_converter/project_variables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | ProjectVariables 25 | ================ 26 | Manage creation of CMake variables that will be used during compilation 27 | """ 28 | 29 | import os 30 | 31 | from cmake_converter.utils import replace_vs_vars_with_cmake_vars 32 | from cmake_converter.utils import cleaning_output, message, check_for_relative_in_path 33 | from cmake_converter.utils import set_native_slash, get_dir_name_with_vars 34 | 35 | 36 | class ProjectVariables: 37 | """ 38 | Class that manages project variables 39 | """ 40 | 41 | @staticmethod 42 | def set_target_name(context, target_name_value): 43 | """ Evaluates target name and sets it into project context """ 44 | context.settings[context.current_setting]['TARGET_NAME'] = [replace_vs_vars_with_cmake_vars( 45 | context, 46 | target_name_value 47 | )] 48 | message(context, 'TargetName = {}'.format(target_name_value), '') 49 | 50 | @staticmethod 51 | def set_output_dir_impl(context, output_node_text): 52 | """ 53 | 54 | :param context: 55 | :param output_node_text: 56 | :return: 57 | """ 58 | output_path = cleaning_output(context, output_node_text) 59 | output_path = output_path.replace('\n', '') 60 | output_path = check_for_relative_in_path(context, output_path) 61 | context.settings[context.current_setting]['OUTPUT_DIRECTORY'] = [output_path] 62 | message(context, 'Output Dir = {}'.format(output_path), '') 63 | 64 | @staticmethod 65 | def set_output_file_impl(context, output_file_node_text): 66 | """ Common routine for evaluating path and name of output file """ 67 | if output_file_node_text: 68 | # next 2 properties are special. check Default.cmake for understanding 69 | if not context.settings[context.current_setting]['OUTPUT_DIRECTORY']: 70 | context.settings[context.current_setting]['OUTPUT_DIRECTORY'] = \ 71 | ['${OUTPUT_DIRECTORY}'] 72 | if not context.settings[context.current_setting]['TARGET_NAME']: 73 | context.settings[context.current_setting]['TARGET_NAME'] = ['${TARGET_NAME}'] 74 | 75 | output_path = context.settings[context.current_setting]['OUTPUT_DIRECTORY'][0] 76 | output_file = cleaning_output(context, output_file_node_text) 77 | output_file = output_file.replace('${OUTPUT_DIRECTORY}', output_path) 78 | output_path = os.path.dirname(output_file) 79 | name, _ = os.path.splitext(os.path.basename(output_file)) 80 | name = name.replace( 81 | '${TARGET_NAME}', 82 | context.settings[context.current_setting]['TARGET_NAME'][0] 83 | ) 84 | context.settings[context.current_setting]['TARGET_NAME'] = \ 85 | [replace_vs_vars_with_cmake_vars(context, name)] 86 | 87 | output_path = check_for_relative_in_path(context, output_path) 88 | context.settings[context.current_setting]['OUTPUT_DIRECTORY'] = [output_path] 89 | 90 | message( 91 | context, 92 | 'Output File : dir="{}" name="{}"'.format( 93 | context.settings[context.current_setting]['OUTPUT_DIRECTORY'][0], 94 | context.settings[context.current_setting]['TARGET_NAME']), 95 | '') 96 | 97 | @staticmethod 98 | def set_path_and_name_from_node(context, node_name, file_path, path_property, name_property): 99 | """ Common routine for evaluating path and name from node text """ 100 | if not file_path: 101 | return 102 | 103 | file_path = replace_vs_vars_with_cmake_vars(context, file_path) 104 | file_path = set_native_slash(file_path) 105 | path, name = get_dir_name_with_vars(context, file_path) 106 | result_name = replace_vs_vars_with_cmake_vars(context, name) 107 | result_path = cleaning_output(context, path) 108 | result_path = check_for_relative_in_path(context, result_path) 109 | 110 | message(context, '{} directory = {}'.format(node_name, result_path), '') 111 | message(context, '{} name = {}'.format(node_name, result_name), '') 112 | 113 | context.settings[context.current_setting][path_property] = [result_path] 114 | context.settings[context.current_setting][name_property] = [result_name] 115 | -------------------------------------------------------------------------------- /test/datatest/sln/bar.vfproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /cmake_converter/context.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Context object descriptor 25 | ========================= 26 | 27 | """ 28 | 29 | import os 30 | import time 31 | from multiprocessing import cpu_count 32 | from collections import OrderedDict 33 | import copy 34 | 35 | from cmake_converter.utils import message 36 | from cmake_converter.writer import CMakeWriter 37 | 38 | 39 | class Context: 40 | """ 41 | Converter context 42 | """ 43 | def __init__(self): 44 | self.time0 = time.time() 45 | self.jobs = cpu_count() 46 | self.xml_data = {} 47 | self.vcxproj_path = '' 48 | self.solution_path = '' 49 | self.target_number = None 50 | self.project_languages = set() 51 | self.target_languages = [] 52 | self.sln_deps = [] 53 | self.target_references = [] 54 | self.add_lib_deps = False 55 | self.packages_config_path = '' 56 | self.import_projects = [] 57 | self.packages = [] 58 | 59 | self.projects_regexp = '.*' 60 | self.additional_code = None 61 | self.dry = False 62 | self.verbose = False 63 | self.warn_level = 2 64 | self.private_include_directories = False 65 | self.ignore_absent_sources = False 66 | self.indent = ' ' 67 | 68 | self.sln_configurations_map = {} 69 | self.project_folder = '' 70 | self.configurations_to_parse = set() 71 | self.cmake = '' 72 | self.project_name = '' 73 | self.root_namespace = '' 74 | self.target_windows_version = '' 75 | self.default_property_sheet = '' 76 | self.sources = {} 77 | self.headers = {} 78 | self.other_project_files = {} 79 | self.source_groups = {} 80 | self.excluded_from_build = False 81 | self.file_contexts = OrderedDict() 82 | self.supported_architectures = set() 83 | self.settings = OrderedDict() 84 | self.current_setting = (None, None) # (conf, arch) 85 | self.current_node = None 86 | self.warnings_count = 0 87 | # helpers 88 | self.parser = None 89 | self.variables = None 90 | self.files = None 91 | self.flags = None 92 | self.dependencies = None 93 | self.utils = None 94 | self.writer = CMakeWriter() 95 | 96 | def clone(self): 97 | """ 98 | Deep clone of Context 99 | 100 | :return: 101 | """ 102 | return copy.deepcopy(self) 103 | 104 | @staticmethod 105 | def get_project_initialization_dict(): 106 | """ Get initializer functors mapped to path keys """ 107 | return {} 108 | 109 | def init(self, source_project_path, cmake_lists_destination_dir): 110 | """ 111 | Initialize instance of Context with Initializer 112 | 113 | :param source_project_path: 114 | :param cmake_lists_destination_dir: 115 | :return: 116 | """ 117 | 118 | message( 119 | self, 120 | 'Initialization data for conversion of project {}'.format(self.vcxproj_path), 121 | '' 122 | ) 123 | 124 | if not os.path.exists(source_project_path): 125 | message( 126 | self, 127 | "{} project file doesn't exist ... skipping ".format(source_project_path), 128 | 'error' 129 | ) 130 | return False 131 | 132 | for _, proj_config in self.sln_configurations_map.items(): 133 | self.configurations_to_parse.add(proj_config) 134 | 135 | context_initializer_map = self.get_project_initialization_dict() 136 | 137 | for key, initializer in context_initializer_map.items(): 138 | if key in source_project_path: 139 | initializer() 140 | self.project_name = os.path.basename(os.path.splitext(source_project_path)[0]) 141 | self.vcxproj_path = source_project_path 142 | self.set_cmake_lists_path(cmake_lists_destination_dir) 143 | self.utils.init_context_current_setting(self) # None - global settings 144 | self.flags.prepare_context_for_flags(self) 145 | return True 146 | 147 | message(self, 'Unknown project type at {}'.format(source_project_path), 'error') 148 | return False 149 | 150 | def set_cmake_lists_path(self, cmake_lists): 151 | """ 152 | Set CMakeLists.txt path in context, for given project 153 | 154 | :param cmake_lists: path of CMakeLists related to project name 155 | :type cmake_lists: str 156 | """ 157 | 158 | self.cmake = None 159 | 160 | if cmake_lists: 161 | if os.path.exists(cmake_lists): 162 | self.cmake = cmake_lists 163 | 164 | if self.cmake is None: 165 | message( 166 | self, 167 | 'Path "{}" for CMakeLists.txt is wrong. ' 168 | 'It will be created in working directory.'.format(cmake_lists), 169 | 'warn' 170 | ) 171 | self.cmake = 'CMakeLists.txt' 172 | 173 | return self.cmake 174 | -------------------------------------------------------------------------------- /cmake_converter/data_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Data Files 25 | ========== 26 | Manage the **VS Project** data and creation of **CMakeLists.txt** file 27 | """ 28 | 29 | import os 30 | import sys 31 | from lxml import etree 32 | 33 | from cmake_converter.utils import message, get_actual_filename, set_native_slash 34 | 35 | 36 | def search_file_path(context, xml_file): 37 | """ Util function for checking file in path. """ 38 | xml_file = set_native_slash(xml_file) 39 | 40 | found_xml_file = get_actual_filename(context, xml_file) 41 | 42 | if found_xml_file is None: 43 | message( 44 | context, 45 | '{} file not exists. '.format(xml_file), 46 | 'error' 47 | ) 48 | return None 49 | 50 | if found_xml_file != xml_file: 51 | message( 52 | context, 53 | 'file reference probably has wrong case {}'.format(xml_file), 54 | 'warn4' 55 | ) 56 | 57 | return found_xml_file 58 | 59 | 60 | def get_vcxproj_data(context, vs_project): 61 | """ 62 | Return xml data from "vcxproj" file 63 | 64 | :param context: the context of converter 65 | :type context: Context 66 | :param vs_project: the vcxproj file 67 | :type vs_project: str 68 | :return: dict with VS Project data 69 | :rtype: dict 70 | """ 71 | 72 | vcxproj = get_xml_data(context, vs_project) 73 | 74 | if vcxproj is not None and 'http://schemas.microsoft.com' not in vcxproj['ns']['ns']: 75 | message( 76 | context, 77 | '{} file cannot be import, because this file does not seem to comply with' 78 | ' Microsoft xml data !'.format(vs_project), 79 | 'error' 80 | ) 81 | sys.exit(1) 82 | 83 | return vcxproj 84 | 85 | 86 | def get_xml_data(context, xml_file): 87 | """ 88 | Return xml data from "xml" file 89 | 90 | :param context: the context of converter 91 | :type context: Context 92 | :param xml_file: the xml file 93 | :type xml_file: str 94 | :return: dict with VS Project data 95 | :rtype: dict 96 | """ 97 | 98 | xml = {} 99 | xml_file = search_file_path(context, xml_file) 100 | if xml_file is None: 101 | return None 102 | 103 | try: 104 | tree = etree.parse(xml_file) 105 | namespace = str(tree.getroot().nsmap) 106 | ns = {'ns': namespace.partition('\'')[-1].rpartition('\'')[0]} 107 | xml['tree'] = tree 108 | xml['ns'] = ns 109 | except (OSError, IOError): # pragma: no cover 110 | message( 111 | context, 112 | '{} file cannot be import. ' 113 | 'Please, verify you have rights to this directory or file exists !'.format(xml_file), 114 | 'error' 115 | ) 116 | sys.exit(1) 117 | except etree.XMLSyntaxError: # pragma: no cover 118 | message( 119 | context, 120 | 'File {} is not a ".xml" file or XML is broken !'.format(xml_file), 121 | 'error' 122 | ) 123 | sys.exit(1) 124 | 125 | return xml 126 | 127 | 128 | def get_propertygroup(target_platform, attributes=''): 129 | """ 130 | Return "property_groups" value for wanted platform and target 131 | 132 | :param target_platform: wanted target: debug | release 133 | :type target_platform: tuple[str,str] 134 | :param attributes: attributes to add to namespace 135 | :type attributes: str 136 | :return: "property_groups" value 137 | :rtype: str 138 | """ 139 | 140 | prop = \ 141 | '//ns:PropertyGroup[@Condition="\'$(Configuration)|$(Platform)\'==\'{}\'"{}]'.format( 142 | '|'.join(target_platform), attributes) 143 | 144 | return prop 145 | 146 | 147 | def get_definitiongroup(target_platform): 148 | """ 149 | Return ItemDefinitionGroup namespace depends on platform and target 150 | 151 | :param target_platform: wanted target: debug | release 152 | :type target_platform: tuple[str,str] 153 | :return: wanted ItemDefinitionGroup namespace 154 | :rtype: str 155 | """ 156 | 157 | item = \ 158 | '//ns:ItemDefinitionGroup[@Condition="\'$(Configuration)|' \ 159 | '$(Platform)\'==\'{}\'"]'.format('|'.join(target_platform)) 160 | 161 | return item 162 | 163 | 164 | def get_cmake_lists(context, cmake_path=None, open_type='w'): 165 | """ 166 | Create CMakeLists.txt file in wanted "cmake_path" 167 | 168 | :param context: the context of converter 169 | :type context: Context 170 | :param cmake_path: path where CMakeLists.txt should be open 171 | :type cmake_path: str 172 | :param open_type: type that CMakeLists.txt should be opened 173 | :type open_type: str 174 | :return: cmake file wrapper opened 175 | :rtype: _io.TextIOWrapper 176 | """ 177 | 178 | if not cmake_path: 179 | cmake_path = os.getcwd() 180 | message(context, 'CMakeLists dir is current directory.', 'warn') 181 | 182 | cmake = os.path.join(cmake_path, 'CMakeLists.txt') 183 | 184 | if not os.path.exists(cmake) and open_type == 'r': 185 | return None 186 | 187 | message(context, 'CMakeLists.txt will be written to : ' + cmake, '') 188 | 189 | with open(cmake, open_type, newline='\n', encoding='utf-8') as cmake_file: 190 | yield cmake_file 191 | 192 | return None 193 | -------------------------------------------------------------------------------- /test/test_project_variables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | import os 24 | import unittest 25 | 26 | from cmake_converter.visual_studio.context import VSContext 27 | from cmake_converter.data_files import get_vcxproj_data, get_cmake_lists 28 | 29 | 30 | @unittest.skip("TestProjectVariables tests skipping") 31 | class TestProjectVariables(unittest.TestCase): 32 | """ 33 | This file test methods of ProjectVariables class. 34 | """ 35 | 36 | cur_dir = os.path.dirname(os.path.realpath(__file__)) 37 | context = VSContext() 38 | vcxproj_data_test = get_vcxproj_data(context, '%s/datatest/foo.vcxproj' % cur_dir) 39 | cmake_lists_test = get_cmake_lists(context, cur_dir) 40 | 41 | data_test = { 42 | 'cmake': cmake_lists_test, 43 | 'cmakeoutput': None, 44 | 'vcxproj': vcxproj_data_test, 45 | 'include': None, 46 | 'additional': None, 47 | } 48 | 49 | def test_init_project_variables(self): 50 | """Initialize Project Variables""" 51 | 52 | under_test = VCXProjectVariables(self.data_test) 53 | 54 | self.assertTrue(under_test.tree) 55 | self.assertTrue(under_test.ns) 56 | self.assertTrue(under_test.cmake) 57 | self.assertFalse(under_test.output) 58 | self.assertIsNotNone(under_test.cmake_outputs) 59 | 60 | def test_add_project_variables(self): 61 | """Add Project Variables""" 62 | 63 | self.data_test['cmake'] = get_cmake_lists(context, self.cur_dir) 64 | under_test = VCXProjectVariables(self.data_test) 65 | 66 | under_test.add_project_variables() 67 | 68 | self.data_test['cmake'].close() 69 | 70 | cmakelists_test = open('%s/CMakeLists.txt' % self.cur_dir) 71 | content_test = cmakelists_test.read() 72 | 73 | self.assertTrue('set(PROJECT_NAME core)' in content_test) 74 | 75 | cmakelists_test.close() 76 | 77 | def test_add_outputs_variables(self): 78 | """Add Outputs Variables""" 79 | 80 | # TODO If NO output is given 81 | # self.data_test['cmake'] = get_cmake_lists(context, self.cur_dir) 82 | under_test = VCXProjectVariables(self.data_test) 83 | # 84 | # under_test.add_project_variables() 85 | # under_test.add_outputs_variables() 86 | # 87 | # self.data_test['cmake'].close() 88 | # 89 | # cmakelists_test = open('%s/CMakeLists.txt' % self.cur_dir) 90 | # content_test = cmakelists_test.read() 91 | # 92 | # self.assertTrue('OUTPUT_DEBUG ../../../build/vc2017_x64d/bin/', content_test) 93 | # self.assertTrue('OUTPUT_REL ../../../build/vc2017_x64/bin/' in content_test) 94 | # 95 | # cmakelists_test.close() 96 | 97 | # If output is given 98 | under_test.output = '../output_binaries' 99 | under_test.cmake = get_cmake_lists(context, self.cur_dir) 100 | under_test.add_outputs_variables() 101 | 102 | under_test.cmake.close() 103 | 104 | cmakelists_test = open('%s/CMakeLists.txt' % self.cur_dir) 105 | content_test = cmakelists_test.read() 106 | 107 | self.assertTrue('OUTPUT_DEBUG ../output_binaries/${CMAKE_BUILD_TYPE}', content_test) 108 | self.assertTrue('OUTPUT_REL ../output_binaries/${CMAKE_BUILD_TYPE}' in content_test) 109 | 110 | cmakelists_test.close() 111 | 112 | def test_add_cmake_project(self): 113 | """Add CMake Project""" 114 | 115 | self.data_test['cmake'] = get_cmake_lists(context, self.cur_dir) 116 | under_test = VCXProjectVariables(self.data_test) 117 | 118 | # Case CXX languages 119 | under_test.add_cmake_project(['cpp']) 120 | 121 | self.data_test['cmake'].close() 122 | 123 | cmakelists_test = open('%s/CMakeLists.txt' % self.cur_dir, 'r') 124 | content_test = cmakelists_test.read() 125 | 126 | self.assertTrue('project(${PROJECT_NAME} CXX)' in content_test) 127 | 128 | cmakelists_test.close() 129 | 130 | # Case C languages 131 | under_test.cmake = get_cmake_lists(context, self.cur_dir) 132 | under_test.add_cmake_project(['c']) 133 | 134 | under_test.cmake.close() 135 | 136 | cmakelists_test = open('%s/CMakeLists.txt' % self.cur_dir, 'r') 137 | content_test = cmakelists_test.read() 138 | 139 | self.assertTrue('project(${PROJECT_NAME} C)' in content_test) 140 | 141 | cmakelists_test.close() 142 | 143 | def test_add_artefact_target_outputs(self): 144 | """Add Artefact Target Outputs""" 145 | 146 | self.data_test['cmake'] = get_cmake_lists(context, self.cur_dir) 147 | under_test = VCXProjectVariables(self.data_test) 148 | 149 | under_test.add_cmake_output_directories() 150 | 151 | self.data_test['cmake'].close() 152 | 153 | cmakelists_test = open('%s/CMakeLists.txt' % self.cur_dir, 'r') 154 | content_test = cmakelists_test.read() 155 | 156 | self.assertTrue( 157 | 'set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_DIR}/${OUTPUT_DEBUG}")' in 158 | content_test 159 | ) 160 | self.assertTrue( 161 | 'set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_DIR}/${OUTPUT_DEBUG}")' in 162 | content_test 163 | ) 164 | self.assertTrue( 165 | 'set(CMAKE_EXECUTABLE_OUTPUT_DIRECTORY "${PROJECT_DIR}/${OUTPUT_DEBUG}' in 166 | content_test 167 | ) 168 | 169 | self.assertTrue( 170 | 'set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_DIR}/${OUTPUT_RELEASE}")' in 171 | content_test 172 | ) 173 | self.assertTrue( 174 | 'set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_DIR}/${OUTPUT_RELEASE}")' in 175 | content_test 176 | ) 177 | self.assertTrue( 178 | 'set(CMAKE_EXECUTABLE_OUTPUT_DIRECTORY "${PROJECT_DIR}/${OUTPUT_RELEASE}' in 179 | content_test 180 | ) 181 | 182 | cmakelists_test.close() 183 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/vfproj/dependencies.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Module that handles dependencies information for fortran projects. 25 | """ 26 | 27 | from cmake_converter.dependencies import Dependencies 28 | from cmake_converter.utils import message, prepare_build_event_cmd_line_for_cmake,\ 29 | check_for_relative_in_path, cleaning_output 30 | 31 | 32 | class VFDependencies(Dependencies): 33 | """ 34 | Class that handles dependencies information for fortran projects. 35 | """ 36 | 37 | @staticmethod 38 | def set_target_references(context): 39 | """ Sets target references to context """ 40 | if context.sln_deps: 41 | context.target_references = context.target_references + context.sln_deps 42 | message(context, 'References : {}'.format(context.target_references), '') 43 | 44 | def set_target_additional_dependencies(self, context, flag_name, ad_libs, node): 45 | """ Handles additional link dependencies """ 46 | del flag_name, node 47 | self.set_target_additional_dependencies_impl(context, ad_libs, r'[; ]+') 48 | 49 | @staticmethod 50 | def set_target_additional_library_directories(context, flag_name, 51 | additional_library_directories, node): 52 | """ 53 | Find and set additional library directories in context 54 | 55 | """ 56 | del flag_name, node 57 | 58 | if additional_library_directories: 59 | list_depends = additional_library_directories.replace( 60 | '%(AdditionalLibraryDirectories)', '' 61 | ) 62 | if list_depends != '': 63 | add_lib_dirs = [] 64 | for d in list_depends.split(';'): 65 | d = d.strip() 66 | if d != '': 67 | add_lib_dirs.append( 68 | check_for_relative_in_path( 69 | context, 70 | cleaning_output(context, d) 71 | ) 72 | ) 73 | message(context, 74 | 'Additional Library Directories = {}'.format(add_lib_dirs), '') 75 | context.settings[context.current_setting]['target_link_dirs'] = add_lib_dirs 76 | 77 | @staticmethod 78 | def __set_target_build_events(context, node, value_name, event_type, command_value): 79 | """ 80 | General routine for setting build events 81 | 82 | :param context: 83 | :param value_name: 84 | :param event_type: 85 | :param command_value: 86 | :return: 87 | """ 88 | commands = [] 89 | for build_event in command_value.split('\n'): 90 | build_event = build_event.strip() 91 | if build_event: 92 | cmake_build_event = prepare_build_event_cmd_line_for_cmake( 93 | context, 94 | build_event 95 | ) 96 | commands.append(cmake_build_event) 97 | 98 | comment = '' 99 | if 'Description' in node.attrib: 100 | comment = node.attrib['Description'] 101 | output = '' 102 | if 'Outputs' in node.attrib: 103 | output = node.attrib['Outputs'] 104 | 105 | event_data = { 106 | 'commands': commands, 107 | 'comment': comment, 108 | 'output': output, 109 | } 110 | context.settings[context.current_setting][value_name] = event_data 111 | message(context, '{} events for {}: {}' 112 | .format(event_type, context.current_setting, commands), 'info') 113 | 114 | @staticmethod 115 | def __is_excluded_from_build(node): 116 | """ 117 | Check weather node content is excluded from build 118 | 119 | :param node: 120 | :return: 121 | """ 122 | if 'ExcludedFromBuild' in node.attrib: 123 | return node.attrib['ExcludedFromBuild'] == 'true' 124 | return False 125 | 126 | def set_target_pre_build_events(self, context, name, command_value, node): 127 | """ 128 | Setting of pre build event to context 129 | 130 | :param context: 131 | :param name: 132 | :param command_value: 133 | :param node: 134 | :return: 135 | """ 136 | del name 137 | 138 | if self.__is_excluded_from_build(node): 139 | return 140 | self.__set_target_build_events( 141 | context, 142 | node, 143 | 'pre_build_events', 144 | 'Pre build', 145 | command_value 146 | ) 147 | 148 | def set_target_pre_link_events(self, context, name, command_value, node): 149 | """ 150 | Setting of pre link event to context 151 | 152 | :param context: 153 | :param name: 154 | :param command_value: 155 | :param node: 156 | :return: 157 | """ 158 | del name 159 | 160 | if self.__is_excluded_from_build(node): 161 | return 162 | self.__set_target_build_events( 163 | context, 164 | node, 165 | 'pre_link_events', 166 | 'Pre link', 167 | command_value 168 | ) 169 | 170 | def set_target_post_build_events(self, context, name, command_value, node): 171 | """ 172 | Setting of post build event to context 173 | 174 | :param context: 175 | :param name: 176 | :param command_value: 177 | :param node: 178 | :return: 179 | """ 180 | del name 181 | 182 | if self.__is_excluded_from_build(node): 183 | return 184 | self.__set_target_build_events( 185 | context, 186 | node, 187 | 'post_build_events', 188 | 'Post build', 189 | command_value 190 | ) 191 | 192 | def set_custom_build_event(self, context, name, command_value, node): 193 | """ 194 | Setting of custom build event to context 195 | :param context: 196 | :param name: 197 | :param command_value: 198 | :param node: 199 | :return: 200 | """ 201 | del name 202 | 203 | if self.__is_excluded_from_build(node): 204 | return 205 | self.__set_target_build_events( 206 | context, 207 | node, 208 | 'custom_build_events', 209 | 'Custom build', 210 | command_value 211 | ) 212 | -------------------------------------------------------------------------------- /cmake_converter/project_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | ProjectFiles 25 | ============= 26 | Manages the recovery of project files 27 | """ 28 | 29 | import os 30 | import ntpath 31 | import copy 32 | 33 | from cmake_converter.utils import take_name_from_list_case_ignore, normalize_path 34 | from cmake_converter.utils import message, set_unix_slash 35 | 36 | 37 | class ProjectFiles: 38 | """ 39 | Class that collects and store project files 40 | """ 41 | 42 | def __init__(self): 43 | self.languages = [] 44 | self.file_lists = {} 45 | self.file_lists_for_include_paths = {} 46 | 47 | def include_directive_case_check(self, context, file_path_name, file_lists_for_include_paths): 48 | """ Dummy to fix crash """ 49 | 50 | @staticmethod 51 | def __create_file_context(context): 52 | file_context = copy.copy(context) 53 | file_context.settings = {} 54 | file_context.flags = copy.copy(context.flags) 55 | file_context.flags.__init__() 56 | file_context.sln_configurations_map = copy.copy(context.sln_configurations_map) 57 | file_context.file_contexts = None 58 | file_context.warnings_count = 0 59 | for setting in context.settings: # copy settings 60 | file_context.current_setting = setting 61 | file_context.utils.init_context_current_setting(file_context) 62 | file_context.current_setting = (None, None) 63 | return file_context 64 | 65 | def __add_file_into_container(self, context, **kwargs): 66 | 67 | files_container = kwargs['files_container'] 68 | file_path = kwargs['file_path'] 69 | file_name = kwargs['file_name'] 70 | source_group = kwargs['source_group'] 71 | 72 | real_name = take_name_from_list_case_ignore(context, self.file_lists[file_path], 73 | file_name) 74 | if real_name: 75 | name_to_add = real_name 76 | else: 77 | if context.ignore_absent_sources: 78 | return None 79 | name_to_add = file_name 80 | message(context, 'Adding absent {} file into project files' 81 | .format(file_name), 'warn') 82 | 83 | files_container[file_path].append(name_to_add) 84 | file_path_name = os.path.normpath(os.path.join(file_path, name_to_add)) 85 | file_path_name = set_unix_slash(file_path_name) 86 | if source_group not in context.source_groups: 87 | context.source_groups[source_group] = [] 88 | context.source_groups[source_group].append(file_path_name) 89 | context.source_groups[source_group].sort(key=str.lower) 90 | if real_name: 91 | self.include_directive_case_check(context, 92 | file_path_name, 93 | self.file_lists_for_include_paths) 94 | context.file_contexts[file_path_name] = self.__create_file_context(context) 95 | return context.file_contexts[file_path_name] 96 | 97 | def add_file_from_node(self, context, **kwargs): 98 | """ 99 | Adds file into source group and creates file context using into from xml node 100 | """ 101 | files_container = kwargs['files_container'] 102 | file_node = kwargs['file_node'] 103 | file_node_attr = kwargs['file_node_attr'] 104 | source_group = kwargs['source_group'] 105 | 106 | if file_node.get(file_node_attr) is not None: 107 | node_text = str(file_node.get(file_node_attr)) 108 | if not node_text.rpartition('.')[-1] in self.languages: 109 | self.languages.append(node_text.rpartition('.')[-1]) 110 | file_path, file_name = ntpath.split(node_text) 111 | vcxproj_dir = os.path.dirname(context.vcxproj_path) 112 | file_path = normalize_path(context, vcxproj_dir, file_path, False, False) 113 | if file_path not in self.file_lists: 114 | self.file_lists[file_path] = [] 115 | if os.path.exists(os.path.join(vcxproj_dir, file_path)): 116 | self.file_lists[file_path] = os.listdir(os.path.join(vcxproj_dir, file_path)) 117 | if file_path not in files_container: 118 | files_container[file_path] = [] 119 | if file_name not in files_container[file_path]: 120 | return self.__add_file_into_container( 121 | context, 122 | files_container=files_container, 123 | file_path=file_path, 124 | file_name=file_name, 125 | source_group=source_group 126 | ) 127 | return None 128 | 129 | def init_file_lists_for_include_paths(self, context): 130 | """ 131 | For include directive case ad path checking. Works only with vfproj. 132 | :param context: 133 | :return: 134 | """ 135 | vcxproj_dir = os.path.dirname(context.vcxproj_path) 136 | for setting in context.settings: 137 | for include_path in context.settings[setting]['inc_dirs_list']: 138 | if include_path not in self.file_lists_for_include_paths: 139 | abs_include_path = os.path.normpath(os.path.join(vcxproj_dir, include_path)) 140 | if os.path.exists(abs_include_path): 141 | self.file_lists_for_include_paths[abs_include_path]\ 142 | = set(os.listdir(abs_include_path)) 143 | 144 | def apply_files_to_context(self, context): 145 | """ Analyzes collected set of files and initializes necessary variables """ 146 | message(context, "Source files extensions found: {}".format(self.languages), 'INFO') 147 | 148 | def find_cmake_target_languages(self, context): 149 | """ 150 | Add CMake Project 151 | 152 | """ 153 | 154 | cpp_extensions = ['cc', 'cp', 'cxx', 'cpp', 'CPP', 'c++', 'C'] 155 | 156 | available_language = {'c': 'C'} 157 | available_language.update(dict.fromkeys(cpp_extensions, 'CXX')) 158 | 159 | fortran_extensions = ['F90', 'F', 'f90', 'f', 'fi', 'FI'] 160 | available_language.update(dict.fromkeys(fortran_extensions, 'Fortran')) 161 | 162 | target_languages_set = set() 163 | for lang in self.languages: 164 | if lang in available_language: 165 | target_languages_set.add(available_language[lang]) 166 | 167 | target_languages = list(target_languages_set) 168 | target_languages.sort() 169 | for project_language in target_languages: 170 | context.project_languages.add(project_language) 171 | context.target_languages = target_languages 172 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help 18 | help: 19 | @echo "Please use \`make ' where is one of" 20 | @echo " html to make standalone HTML files" 21 | @echo " dirhtml to make HTML files named index.html in directories" 22 | @echo " singlehtml to make a single large HTML file" 23 | @echo " pickle to make pickle files" 24 | @echo " json to make JSON files" 25 | @echo " htmlhelp to make HTML files and a HTML help project" 26 | @echo " qthelp to make HTML files and a qthelp project" 27 | @echo " applehelp to make an Apple Help Book" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " epub3 to make an epub3" 31 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 32 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 33 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 34 | @echo " text to make text files" 35 | @echo " man to make manual pages" 36 | @echo " texinfo to make Texinfo files" 37 | @echo " info to make Texinfo files and run them through makeinfo" 38 | @echo " gettext to make PO message catalogs" 39 | @echo " changes to make an overview of all changed/added/deprecated items" 40 | @echo " xml to make Docutils-native XML files" 41 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 42 | @echo " linkcheck to check all external links for integrity" 43 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 44 | @echo " coverage to run coverage check of the documentation (if enabled)" 45 | @echo " dummy to check syntax errors of document sources" 46 | 47 | .PHONY: clean 48 | clean: 49 | rm -rf $(BUILDDIR)/* 50 | 51 | .PHONY: html 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | .PHONY: dirhtml 58 | dirhtml: 59 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 60 | @echo 61 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 62 | 63 | .PHONY: singlehtml 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | .PHONY: pickle 70 | pickle: 71 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 72 | @echo 73 | @echo "Build finished; now you can process the pickle files." 74 | 75 | .PHONY: json 76 | json: 77 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 78 | @echo 79 | @echo "Build finished; now you can process the JSON files." 80 | 81 | .PHONY: htmlhelp 82 | htmlhelp: 83 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 84 | @echo 85 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 86 | ".hhp project file in $(BUILDDIR)/htmlhelp." 87 | 88 | .PHONY: qthelp 89 | qthelp: 90 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 91 | @echo 92 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 93 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 94 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cmake_converter.qhcp" 95 | @echo "To view the help file:" 96 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cmake_converter.qhc" 97 | 98 | .PHONY: applehelp 99 | applehelp: 100 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 101 | @echo 102 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 103 | @echo "N.B. You won't be able to view it unless you put it in" \ 104 | "~/Library/Documentation/Help or install it in your application" \ 105 | "bundle." 106 | 107 | .PHONY: devhelp 108 | devhelp: 109 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 110 | @echo 111 | @echo "Build finished." 112 | @echo "To view the help file:" 113 | @echo "# mkdir -p $$HOME/.local/share/devhelp/cmake_converter" 114 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cmake_converter" 115 | @echo "# devhelp" 116 | 117 | .PHONY: epub 118 | epub: 119 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 120 | @echo 121 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 122 | 123 | .PHONY: epub3 124 | epub3: 125 | $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 126 | @echo 127 | @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." 128 | 129 | .PHONY: latex 130 | latex: 131 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 132 | @echo 133 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 134 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 135 | "(use \`make latexpdf' here to do that automatically)." 136 | 137 | .PHONY: latexpdf 138 | latexpdf: 139 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 140 | @echo "Running LaTeX files through pdflatex..." 141 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 142 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 143 | 144 | .PHONY: latexpdfja 145 | latexpdfja: 146 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 147 | @echo "Running LaTeX files through platex and dvipdfmx..." 148 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 149 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 150 | 151 | .PHONY: text 152 | text: 153 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 154 | @echo 155 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 156 | 157 | .PHONY: man 158 | man: 159 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 160 | @echo 161 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 162 | 163 | .PHONY: texinfo 164 | texinfo: 165 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 166 | @echo 167 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 168 | @echo "Run \`make' in that directory to run these through makeinfo" \ 169 | "(use \`make info' here to do that automatically)." 170 | 171 | .PHONY: info 172 | info: 173 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 174 | @echo "Running Texinfo files through makeinfo..." 175 | make -C $(BUILDDIR)/texinfo info 176 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 177 | 178 | .PHONY: gettext 179 | gettext: 180 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 181 | @echo 182 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 183 | 184 | .PHONY: changes 185 | changes: 186 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 187 | @echo 188 | @echo "The overview file is in $(BUILDDIR)/changes." 189 | 190 | .PHONY: linkcheck 191 | linkcheck: 192 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 193 | @echo 194 | @echo "Link check complete; look for any errors in the above output " \ 195 | "or in $(BUILDDIR)/linkcheck/output.txt." 196 | 197 | .PHONY: doctest 198 | doctest: 199 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 200 | @echo "Testing of doctests in the sources finished, look at the " \ 201 | "results in $(BUILDDIR)/doctest/output.txt." 202 | 203 | .PHONY: coverage 204 | coverage: 205 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 206 | @echo "Testing of coverage in the sources finished, look at the " \ 207 | "results in $(BUILDDIR)/coverage/python.txt." 208 | 209 | .PHONY: xml 210 | xml: 211 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 212 | @echo 213 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 214 | 215 | .PHONY: pseudoxml 216 | pseudoxml: 217 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 218 | @echo 219 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 220 | 221 | .PHONY: dummy 222 | dummy: 223 | $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy 224 | @echo 225 | @echo "Build finished. Dummy builder generates no files." 226 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. epub3 to make an epub3 31 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 32 | echo. text to make text files 33 | echo. man to make manual pages 34 | echo. texinfo to make Texinfo files 35 | echo. gettext to make PO message catalogs 36 | echo. changes to make an overview over all changed/added/deprecated items 37 | echo. xml to make Docutils-native XML files 38 | echo. pseudoxml to make pseudoxml-XML files for display purposes 39 | echo. linkcheck to check all external links for integrity 40 | echo. doctest to run all doctests embedded in the documentation if enabled 41 | echo. coverage to run coverage check of the documentation if enabled 42 | echo. dummy to check syntax errors of document sources 43 | goto end 44 | ) 45 | 46 | if "%1" == "clean" ( 47 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 48 | del /q /s %BUILDDIR%\* 49 | goto end 50 | ) 51 | 52 | 53 | REM Check if sphinx-build is available and fallback to Python version if any 54 | %SPHINXBUILD% 1>NUL 2>NUL 55 | if errorlevel 9009 goto sphinx_python 56 | goto sphinx_ok 57 | 58 | :sphinx_python 59 | 60 | set SPHINXBUILD=python -m sphinx.__init__ 61 | %SPHINXBUILD% 2> nul 62 | if errorlevel 9009 ( 63 | echo. 64 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 65 | echo.installed, then set the SPHINXBUILD environment variable to point 66 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 67 | echo.may add the Sphinx directory to PATH. 68 | echo. 69 | echo.If you don't have Sphinx installed, grab it from 70 | echo.http://sphinx-doc.org/ 71 | exit /b 1 72 | ) 73 | 74 | :sphinx_ok 75 | 76 | 77 | if "%1" == "html" ( 78 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 79 | if errorlevel 1 exit /b 1 80 | echo. 81 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 82 | goto end 83 | ) 84 | 85 | if "%1" == "dirhtml" ( 86 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 87 | if errorlevel 1 exit /b 1 88 | echo. 89 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 90 | goto end 91 | ) 92 | 93 | if "%1" == "singlehtml" ( 94 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 95 | if errorlevel 1 exit /b 1 96 | echo. 97 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 98 | goto end 99 | ) 100 | 101 | if "%1" == "pickle" ( 102 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 103 | if errorlevel 1 exit /b 1 104 | echo. 105 | echo.Build finished; now you can process the pickle files. 106 | goto end 107 | ) 108 | 109 | if "%1" == "json" ( 110 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 111 | if errorlevel 1 exit /b 1 112 | echo. 113 | echo.Build finished; now you can process the JSON files. 114 | goto end 115 | ) 116 | 117 | if "%1" == "htmlhelp" ( 118 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 119 | if errorlevel 1 exit /b 1 120 | echo. 121 | echo.Build finished; now you can run HTML Help Workshop with the ^ 122 | .hhp project file in %BUILDDIR%/htmlhelp. 123 | goto end 124 | ) 125 | 126 | if "%1" == "qthelp" ( 127 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 128 | if errorlevel 1 exit /b 1 129 | echo. 130 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 131 | .qhcp project file in %BUILDDIR%/qthelp, like this: 132 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\cmake_converter.qhcp 133 | echo.To view the help file: 134 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\cmake_converter.ghc 135 | goto end 136 | ) 137 | 138 | if "%1" == "devhelp" ( 139 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 140 | if errorlevel 1 exit /b 1 141 | echo. 142 | echo.Build finished. 143 | goto end 144 | ) 145 | 146 | if "%1" == "epub" ( 147 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 148 | if errorlevel 1 exit /b 1 149 | echo. 150 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 151 | goto end 152 | ) 153 | 154 | if "%1" == "epub3" ( 155 | %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 156 | if errorlevel 1 exit /b 1 157 | echo. 158 | echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. 159 | goto end 160 | ) 161 | 162 | if "%1" == "latex" ( 163 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 164 | if errorlevel 1 exit /b 1 165 | echo. 166 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdf" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "latexpdfja" ( 181 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 182 | cd %BUILDDIR%/latex 183 | make all-pdf-ja 184 | cd %~dp0 185 | echo. 186 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 187 | goto end 188 | ) 189 | 190 | if "%1" == "text" ( 191 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 192 | if errorlevel 1 exit /b 1 193 | echo. 194 | echo.Build finished. The text files are in %BUILDDIR%/text. 195 | goto end 196 | ) 197 | 198 | if "%1" == "man" ( 199 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 200 | if errorlevel 1 exit /b 1 201 | echo. 202 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 203 | goto end 204 | ) 205 | 206 | if "%1" == "texinfo" ( 207 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 208 | if errorlevel 1 exit /b 1 209 | echo. 210 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 211 | goto end 212 | ) 213 | 214 | if "%1" == "gettext" ( 215 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 216 | if errorlevel 1 exit /b 1 217 | echo. 218 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 219 | goto end 220 | ) 221 | 222 | if "%1" == "changes" ( 223 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 224 | if errorlevel 1 exit /b 1 225 | echo. 226 | echo.The overview file is in %BUILDDIR%/changes. 227 | goto end 228 | ) 229 | 230 | if "%1" == "linkcheck" ( 231 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 232 | if errorlevel 1 exit /b 1 233 | echo. 234 | echo.Link check complete; look for any errors in the above output ^ 235 | or in %BUILDDIR%/linkcheck/output.txt. 236 | goto end 237 | ) 238 | 239 | if "%1" == "doctest" ( 240 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 241 | if errorlevel 1 exit /b 1 242 | echo. 243 | echo.Testing of doctests in the sources finished, look at the ^ 244 | results in %BUILDDIR%/doctest/output.txt. 245 | goto end 246 | ) 247 | 248 | if "%1" == "coverage" ( 249 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 250 | if errorlevel 1 exit /b 1 251 | echo. 252 | echo.Testing of coverage in the sources finished, look at the ^ 253 | results in %BUILDDIR%/coverage/python.txt. 254 | goto end 255 | ) 256 | 257 | if "%1" == "xml" ( 258 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 259 | if errorlevel 1 exit /b 1 260 | echo. 261 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 262 | goto end 263 | ) 264 | 265 | if "%1" == "pseudoxml" ( 266 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 267 | if errorlevel 1 exit /b 1 268 | echo. 269 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 270 | goto end 271 | ) 272 | 273 | if "%1" == "dummy" ( 274 | %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy 275 | if errorlevel 1 exit /b 1 276 | echo. 277 | echo.Build finished. Dummy builder generates no files. 278 | goto end 279 | ) 280 | 281 | :end 282 | -------------------------------------------------------------------------------- /cmake_converter/utils.cmake: -------------------------------------------------------------------------------- 1 | # utils file for projects came from visual studio solution with cmake-converter. 2 | 3 | ################################################################################ 4 | # Wrap each token of the command with condition 5 | ################################################################################ 6 | cmake_policy(PUSH) 7 | cmake_policy(SET CMP0054 NEW) 8 | macro(prepare_commands) 9 | unset(TOKEN_ROLE) 10 | unset(COMMANDS) 11 | foreach(TOKEN ${ARG_COMMANDS}) 12 | if("${TOKEN}" STREQUAL "COMMAND") 13 | set(TOKEN_ROLE "KEYWORD") 14 | elseif("${TOKEN_ROLE}" STREQUAL "KEYWORD") 15 | set(TOKEN_ROLE "CONDITION") 16 | elseif("${TOKEN_ROLE}" STREQUAL "CONDITION") 17 | set(TOKEN_ROLE "COMMAND") 18 | elseif("${TOKEN_ROLE}" STREQUAL "COMMAND") 19 | set(TOKEN_ROLE "ARG") 20 | endif() 21 | 22 | if("${TOKEN_ROLE}" STREQUAL "KEYWORD") 23 | list(APPEND COMMANDS "${TOKEN}") 24 | elseif("${TOKEN_ROLE}" STREQUAL "CONDITION") 25 | set(CONDITION ${TOKEN}) 26 | elseif("${TOKEN_ROLE}" STREQUAL "COMMAND") 27 | list(APPEND COMMANDS "$<$:${DUMMY}>$<${CONDITION}:${TOKEN}>") 28 | elseif("${TOKEN_ROLE}" STREQUAL "ARG") 29 | list(APPEND COMMANDS "$<${CONDITION}:${TOKEN}>") 30 | endif() 31 | endforeach() 32 | endmacro() 33 | cmake_policy(POP) 34 | 35 | ################################################################################ 36 | # Transform all the tokens to absolute paths 37 | ################################################################################ 38 | macro(prepare_output) 39 | unset(OUTPUT) 40 | foreach(TOKEN ${ARG_OUTPUT}) 41 | if(IS_ABSOLUTE ${TOKEN}) 42 | list(APPEND OUTPUT "${TOKEN}") 43 | else() 44 | list(APPEND OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/${TOKEN}") 45 | endif() 46 | endforeach() 47 | endmacro() 48 | 49 | ################################################################################ 50 | # Parse add_custom_command_if args. 51 | # 52 | # Input: 53 | # PRE_BUILD - Pre build event option 54 | # PRE_LINK - Pre link event option 55 | # POST_BUILD - Post build event option 56 | # TARGET - Target 57 | # OUTPUT - List of output files 58 | # DEPENDS - List of files on which the command depends 59 | # COMMANDS - List of commands(COMMAND condition1 commannd1 args1 COMMAND 60 | # condition2 commannd2 args2 ...) 61 | # Output: 62 | # OUTPUT - Output files 63 | # DEPENDS - Files on which the command depends 64 | # COMMENT - Comment 65 | # PRE_BUILD - TRUE/FALSE 66 | # PRE_LINK - TRUE/FALSE 67 | # POST_BUILD - TRUE/FALSE 68 | # TARGET - Target name 69 | # COMMANDS - Prepared commands(every token is wrapped in CONDITION) 70 | # NAME - Unique name for custom target 71 | # STEP - PRE_BUILD/PRE_LINK/POST_BUILD 72 | ################################################################################ 73 | function(add_custom_command_if_parse_arguments) 74 | cmake_parse_arguments("ARG" "PRE_BUILD;PRE_LINK;POST_BUILD" "TARGET;COMMENT" "DEPENDS;OUTPUT;COMMANDS" ${ARGN}) 75 | 76 | if(WIN32) 77 | set(DUMMY "cd.") 78 | elseif(UNIX) 79 | set(DUMMY "true") 80 | endif() 81 | 82 | prepare_commands() 83 | prepare_output() 84 | 85 | set(DEPENDS "${ARG_DEPENDS}") 86 | set(COMMENT "${ARG_COMMENT}") 87 | set(PRE_BUILD "${ARG_PRE_BUILD}") 88 | set(PRE_LINK "${ARG_PRE_LINK}") 89 | set(POST_BUILD "${ARG_POST_BUILD}") 90 | set(TARGET "${ARG_TARGET}") 91 | if(PRE_BUILD) 92 | set(STEP "PRE_BUILD") 93 | elseif(PRE_LINK) 94 | set(STEP "PRE_LINK") 95 | elseif(POST_BUILD) 96 | set(STEP "POST_BUILD") 97 | endif() 98 | set(NAME "${TARGET}_${STEP}") 99 | 100 | set(OUTPUT "${OUTPUT}" PARENT_SCOPE) 101 | set(DEPENDS "${DEPENDS}" PARENT_SCOPE) 102 | set(COMMENT "${COMMENT}" PARENT_SCOPE) 103 | set(PRE_BUILD "${PRE_BUILD}" PARENT_SCOPE) 104 | set(PRE_LINK "${PRE_LINK}" PARENT_SCOPE) 105 | set(POST_BUILD "${POST_BUILD}" PARENT_SCOPE) 106 | set(TARGET "${TARGET}" PARENT_SCOPE) 107 | set(COMMANDS "${COMMANDS}" PARENT_SCOPE) 108 | set(STEP "${STEP}" PARENT_SCOPE) 109 | set(NAME "${NAME}" PARENT_SCOPE) 110 | endfunction() 111 | 112 | ################################################################################ 113 | # Add conditional custom command 114 | # 115 | # Generating Files 116 | # The first signature is for adding a custom command to produce an output: 117 | # add_custom_command_if( 118 | # 119 | # 120 | # 121 | # [COMMAND condition command2 [args2...]] 122 | # [DEPENDS [depends...]] 123 | # [COMMENT comment] 124 | # 125 | # Build Events 126 | # add_custom_command_if( 127 | # 128 | # 129 | # 130 | # [COMMAND condition command2 [args2...]] 131 | # [COMMENT comment] 132 | # 133 | # Input: 134 | # output - Output files the command is expected to produce 135 | # condition - Generator expression for wrapping the command 136 | # command - Command-line(s) to execute at build time. 137 | # args - Command`s args 138 | # depends - Files on which the command depends 139 | # comment - Display the given message before the commands are executed at 140 | # build time. 141 | # PRE_BUILD - Run before any other rules are executed within the target 142 | # PRE_LINK - Run after sources have been compiled but before linking the 143 | # binary 144 | # POST_BUILD - Run after all other rules within the target have been 145 | # executed 146 | ################################################################################ 147 | function(add_custom_command_if) 148 | add_custom_command_if_parse_arguments(${ARGN}) 149 | 150 | if(OUTPUT AND TARGET) 151 | message(FATAL_ERROR "Wrong syntax. A TARGET and OUTPUT can not both be specified.") 152 | endif() 153 | 154 | if(OUTPUT) 155 | add_custom_command(OUTPUT ${OUTPUT} 156 | ${COMMANDS} 157 | DEPENDS ${DEPENDS} 158 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 159 | COMMENT ${COMMENT}) 160 | elseif(TARGET) 161 | if(PRE_BUILD AND NOT ${CMAKE_GENERATOR} MATCHES "Visual Studio") 162 | add_custom_target( 163 | ${NAME} 164 | ${COMMANDS} 165 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 166 | COMMENT ${COMMENT}) 167 | add_dependencies(${TARGET} ${NAME}) 168 | else() 169 | add_custom_command( 170 | TARGET ${TARGET} 171 | ${STEP} 172 | ${COMMANDS} 173 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 174 | COMMENT ${COMMENT}) 175 | endif() 176 | else() 177 | message(FATAL_ERROR "Wrong syntax. A TARGET or OUTPUT must be specified.") 178 | endif() 179 | endfunction() 180 | 181 | ################################################################################ 182 | # Use props file for a target and configs 183 | # use_props( ) 184 | # Inside there are following variables: 185 | # PROPS_TARGET - 186 | # PROPS_CONFIG - One of 187 | # PROPS_CONFIG_U - Uppercase PROPS_CONFIG 188 | # Input: 189 | # target - Target to apply props file 190 | # configs - Build configurations to apply props file 191 | # props_file - CMake script 192 | ################################################################################ 193 | macro(use_props TARGET CONFIGS PROPS_FILE) 194 | set(PROPS_TARGET "${TARGET}") 195 | foreach(PROPS_CONFIG ${CONFIGS}) 196 | string(TOUPPER "${PROPS_CONFIG}" PROPS_CONFIG_U) 197 | 198 | get_filename_component(ABSOLUTE_PROPS_FILE "${PROPS_FILE}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}") 199 | if(EXISTS "${ABSOLUTE_PROPS_FILE}") 200 | include("${ABSOLUTE_PROPS_FILE}") 201 | else() 202 | message(WARNING "Corresponding cmake file from props \"${ABSOLUTE_PROPS_FILE}\" doesn't exist") 203 | endif() 204 | endforeach() 205 | endmacro() 206 | 207 | ################################################################################ 208 | # Add compile options to source file 209 | # source_file_compile_options( [compile_options...]) 210 | # Input: 211 | # source_file - Source file 212 | # compile_options - Options to add to COMPILE_FLAGS property 213 | ################################################################################ 214 | function(source_file_compile_options SOURCE_FILE) 215 | if("${ARGC}" LESS_EQUAL "1") 216 | return() 217 | endif() 218 | 219 | get_source_file_property(COMPILE_OPTIONS "${SOURCE_FILE}" COMPILE_OPTIONS) 220 | 221 | if(COMPILE_OPTIONS) 222 | list(APPEND COMPILE_OPTIONS ${ARGN}) 223 | else() 224 | set(COMPILE_OPTIONS "${ARGN}") 225 | endif() 226 | 227 | set_source_files_properties("${SOURCE_FILE}" PROPERTIES COMPILE_OPTIONS "${COMPILE_OPTIONS}") 228 | endfunction() 229 | 230 | ################################################################################ 231 | # Default properties of visual studio projects 232 | ################################################################################ 233 | set(DEFAULT_CXX_PROPS "${CMAKE_CURRENT_LIST_DIR}/DefaultCXX.cmake") 234 | set(DEFAULT_Fortran_PROPS "${CMAKE_CURRENT_LIST_DIR}/DefaultFortran.cmake") 235 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # cmake_converter documentation build configuration file, created by 5 | # sphinx-quickstart on Mon Oct 23 12:02:46 2017. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | # 20 | import os 21 | import sys 22 | sys.path.insert(0, os.path.abspath('../')) 23 | from cmake_converter import __version__, __short_version__ 24 | from cmake_converter import __copyright__, __author__, __application__ 25 | 26 | 27 | # -- General configuration ------------------------------------------------ 28 | 29 | # If your documentation needs a minimal Sphinx version, state it here. 30 | # 31 | # needs_sphinx = '1.0' 32 | 33 | # Add any Sphinx extension module names here, as strings. They can be 34 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 35 | # ones. 36 | extensions = [ 37 | 'sphinx.ext.autodoc', 38 | 'sphinx.ext.intersphinx', 39 | 'sphinx.ext.coverage', 40 | ] 41 | 42 | # Add any paths that contain templates here, relative to this directory. 43 | templates_path = ['_templates'] 44 | 45 | # The suffix(es) of source filenames. 46 | # You can specify multiple suffix as a list of string: 47 | # 48 | # source_suffix = ['.rst', '.md'] 49 | source_suffix = '.rst' 50 | 51 | # The encoding of source files. 52 | # 53 | # source_encoding = 'utf-8-sig' 54 | 55 | # The master toctree document. 56 | master_doc = 'index' 57 | 58 | # General information about the project. 59 | project = __application__ 60 | copyright = __copyright__ 61 | author = __author__ 62 | 63 | # The version info for the project you're documenting, acts as replacement for 64 | # |version| and |release|, also used in various other places throughout the 65 | # built documents. 66 | # 67 | # The short X.Y version. 68 | version = __version__ 69 | # The full version, including alpha/beta/rc tags. 70 | release = __short_version__ 71 | 72 | # The language for content autogenerated by Sphinx. Refer to documentation 73 | # for a list of supported languages. 74 | # 75 | # This is also used if you do content translation via gettext catalogs. 76 | # Usually you set "language" from the command line for these cases. 77 | language = None 78 | 79 | # There are two options for replacing |today|: either, you set today to some 80 | # non-false value, then it is used: 81 | # 82 | # today = '' 83 | # 84 | # Else, today_fmt is used as the format for a strftime call. 85 | # 86 | # today_fmt = '%B %d, %Y' 87 | 88 | # List of patterns, relative to source directory, that match files and 89 | # directories to ignore when looking for source files. 90 | # This patterns also effect to html_static_path and html_extra_path 91 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 92 | 93 | # The reST default role (used for this markup: `text`) to use for all 94 | # documents. 95 | # 96 | # default_role = None 97 | 98 | # If true, '()' will be appended to :func: etc. cross-reference text. 99 | # 100 | # add_function_parentheses = True 101 | 102 | # If true, the current module name will be prepended to all description 103 | # unit titles (such as .. function::). 104 | # 105 | # add_module_names = True 106 | 107 | # If true, sectionauthor and moduleauthor directives will be shown in the 108 | # output. They are ignored by default. 109 | # 110 | # show_authors = False 111 | 112 | # The name of the Pygments (syntax highlighting) style to use. 113 | pygments_style = 'sphinx' 114 | 115 | # A list of ignored prefixes for module index sorting. 116 | # modindex_common_prefix = [] 117 | 118 | # If true, keep warnings as "system message" paragraphs in the built documents. 119 | # keep_warnings = False 120 | 121 | # If true, `todo` and `todoList` produce output, else they produce nothing. 122 | todo_include_todos = False 123 | 124 | 125 | # -- Options for HTML output ---------------------------------------------- 126 | 127 | # The theme to use for HTML and HTML Help pages. See the documentation for 128 | # a list of builtin themes. 129 | # 130 | html_theme = 'sphinx_rtd_theme' 131 | 132 | # Theme options are theme-specific and customize the look and feel of a theme 133 | # further. For a list of options available for each theme, see the 134 | # documentation. 135 | # 136 | # html_theme_options = {} 137 | 138 | # Add any paths that contain custom themes here, relative to this directory. 139 | # html_theme_path = [] 140 | 141 | # The name for this set of Sphinx documents. 142 | # " v documentation" by default. 143 | # 144 | # html_title = 'cmake_converter v0.0.1' 145 | 146 | # A shorter title for the navigation bar. Default is the same as html_title. 147 | # 148 | # html_short_title = None 149 | 150 | # The name of an image file (relative to this directory) to place at the top 151 | # of the sidebar. 152 | # 153 | # html_logo = None 154 | 155 | # The name of an image file (relative to this directory) to use as a favicon of 156 | # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 157 | # pixels large. 158 | # 159 | # html_favicon = None 160 | 161 | # Add any paths that contain custom static files (such as style sheets) here, 162 | # relative to this directory. They are copied after the builtin static files, 163 | # so a file named "default.css" will overwrite the builtin "default.css". 164 | html_static_path = ['_static'] 165 | 166 | # Add any extra paths that contain custom files (such as robots.txt or 167 | # .htaccess) here, relative to this directory. These files are copied 168 | # directly to the root of the documentation. 169 | # 170 | # html_extra_path = [] 171 | 172 | # If not None, a 'Last updated on:' timestamp is inserted at every page 173 | # bottom, using the given strftime format. 174 | # The empty string is equivalent to '%b %d, %Y'. 175 | # 176 | # html_last_updated_fmt = None 177 | 178 | # If true, SmartyPants will be used to convert quotes and dashes to 179 | # typographically correct entities. 180 | # 181 | # html_use_smartypants = True 182 | 183 | # Custom sidebar templates, maps document names to template names. 184 | # 185 | # html_sidebars = {} 186 | 187 | # Additional templates that should be rendered to pages, maps page names to 188 | # template names. 189 | # 190 | # html_additional_pages = {} 191 | 192 | # If false, no module index is generated. 193 | # 194 | # html_domain_indices = True 195 | 196 | # If false, no index is generated. 197 | # 198 | # html_use_index = True 199 | 200 | # If true, the index is split into individual pages for each letter. 201 | # 202 | # html_split_index = False 203 | 204 | # If true, links to the reST sources are added to the pages. 205 | # 206 | # html_show_sourcelink = True 207 | 208 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 209 | # 210 | # html_show_sphinx = True 211 | 212 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 213 | # 214 | # html_show_copyright = True 215 | 216 | # If true, an OpenSearch description file will be output, and all pages will 217 | # contain a tag referring to it. The value of this option must be the 218 | # base URL from which the finished HTML is served. 219 | # 220 | # html_use_opensearch = '' 221 | 222 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 223 | # html_file_suffix = None 224 | 225 | # Language to be used for generating the HTML full-text search index. 226 | # Sphinx supports the following languages: 227 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' 228 | # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh' 229 | # 230 | # html_search_language = 'en' 231 | 232 | # A dictionary with options for the search language support, empty by default. 233 | # 'ja' uses this config value. 234 | # 'zh' user can custom change `jieba` dictionary path. 235 | # 236 | # html_search_options = {'type': 'default'} 237 | 238 | # The name of a javascript file (relative to the configuration directory) that 239 | # implements a search results scorer. If empty, the default will be used. 240 | # 241 | # html_search_scorer = 'scorer.js' 242 | 243 | # Output file base name for HTML help builder. 244 | htmlhelp_basename = 'cmake_converterdoc' 245 | 246 | # -- Options for LaTeX output --------------------------------------------- 247 | 248 | latex_elements = { 249 | # The paper size ('letterpaper' or 'a4paper'). 250 | # 251 | # 'papersize': 'letterpaper', 252 | 253 | # The font size ('10pt', '11pt' or '12pt'). 254 | # 255 | # 'pointsize': '10pt', 256 | 257 | # Additional stuff for the LaTeX preamble. 258 | # 259 | # 'preamble': '', 260 | 261 | # Latex figure (float) alignment 262 | # 263 | # 'figure_align': 'htbp', 264 | } 265 | 266 | # Grouping the document tree into LaTeX files. List of tuples 267 | # (source start file, target name, title, 268 | # author, documentclass [howto, manual, or own class]). 269 | latex_documents = [ 270 | (master_doc, 'cmake_converter.tex', 'cmake\\_converter Documentation', 271 | 'Estrada Matthieu', 'manual'), 272 | ] 273 | 274 | # The name of an image file (relative to this directory) to place at the top of 275 | # the title page. 276 | # 277 | # latex_logo = None 278 | 279 | # For "manual" documents, if this is true, then toplevel headings are parts, 280 | # not chapters. 281 | # 282 | # latex_use_parts = False 283 | 284 | # If true, show page references after internal links. 285 | # 286 | # latex_show_pagerefs = False 287 | 288 | # If true, show URL addresses after external links. 289 | # 290 | # latex_show_urls = False 291 | 292 | # Documents to append as an appendix to all manuals. 293 | # 294 | # latex_appendices = [] 295 | 296 | # It false, will not define \strong, \code, itleref, \crossref ... but only 297 | # \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added 298 | # packages. 299 | # 300 | # latex_keep_old_macro_names = True 301 | 302 | # If false, no module index is generated. 303 | # 304 | # latex_domain_indices = True 305 | 306 | 307 | # -- Options for manual page output --------------------------------------- 308 | 309 | # One entry per manual page. List of tuples 310 | # (source start file, name, description, authors, manual section). 311 | man_pages = [ 312 | (master_doc, 'cmake_converter', 'cmake_converter Documentation', 313 | [author], 1) 314 | ] 315 | 316 | # If true, show URL addresses after external links. 317 | # 318 | # man_show_urls = False 319 | 320 | 321 | # -- Options for Texinfo output ------------------------------------------- 322 | 323 | # Grouping the document tree into Texinfo files. List of tuples 324 | # (source start file, target name, title, author, 325 | # dir menu entry, description, category) 326 | texinfo_documents = [ 327 | (master_doc, 'cmake_converter', 'cmake_converter Documentation', 328 | author, 'cmake_converter', 'One line description of project.', 329 | 'Miscellaneous'), 330 | ] 331 | 332 | # Documents to append as an appendix to all manuals. 333 | # 334 | # texinfo_appendices = [] 335 | 336 | # If false, no module index is generated. 337 | # 338 | # texinfo_domain_indices = True 339 | 340 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 341 | # 342 | # texinfo_show_urls = 'footnote' 343 | 344 | # If true, do not generate a @detailmenu in the "Top" node's menu. 345 | # 346 | # texinfo_no_detailmenu = False 347 | 348 | 349 | # Example configuration for intersphinx: refer to the Python standard library. 350 | intersphinx_mapping = {'https://docs.python.org/': None} 351 | -------------------------------------------------------------------------------- /cmake_converter/visual_studio/vfproj/parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Pavel Liavonau, liavonlida@gmail.com 6 | # Matthieu Estrada, ttamalfor@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | Parser for *.vfproj xml 25 | """ 26 | 27 | from cmake_converter.parser import Parser, StopParseException 28 | from cmake_converter.data_files import get_xml_data 29 | from cmake_converter.utils import make_cmake_configuration 30 | 31 | 32 | class VFParser(Parser): 33 | """ Class for parser of *.vfproj files. """ 34 | 35 | def __init__(self): 36 | Parser.__init__(self) 37 | self.common_diagnostics_value = None 38 | self.common_runtime_checks_value = None 39 | self.source_group = '' 40 | 41 | def get_node_handlers_dict(self, context): 42 | node_handlers = { 43 | 'Platforms': self.do_nothing_node_stub, 44 | 'Configurations': self.__parse_configurations, 45 | 'Configuration': self.__parse_configuration, 46 | 'FileConfiguration': self.__parse_configuration, 47 | 'Tool': self._parse_nodes, 48 | 'Files': self.__parse_files, 49 | 'File': self.do_nothing_node_stub, 50 | 'Filter': self.__parse_filter, 51 | 'Globals': self.do_nothing_node_stub, 52 | } 53 | return node_handlers 54 | 55 | def get_attribute_handlers_dict(self, context): 56 | attributes_handlers = {} 57 | 58 | attributes_handlers.update( 59 | dict.fromkeys(context.flags.flags_handlers.keys(), context.flags.set_flag) 60 | ) 61 | 62 | attributes_handlers.update({ 63 | 'Configuration_Name': self.__parse_configuration_name, 64 | 'FileConfiguration_Name': self.__parse_configuration_name, 65 | 'Configuration_TargetName': self.__parse_target_name, 66 | 'Configuration_OutputDirectory': context.variables.set_output_dir, 67 | 'Configuration_IntermediateDirectory': self.__parse_configuration_intermediate_dir, 68 | 'Configuration_DeleteExtensionsOnClean': self.do_nothing_attr_stub, 69 | 'Configuration_ConfigurationType': self.__parse_configuration_type, 70 | 'Tool_Name': self.__parse_tool_name, 71 | 'VFFortranCompilerTool_PreprocessorDefinitions': self.__parse_preprocessor_definitions, 72 | 'VFFortranCompilerTool_AdditionalIncludeDirectories': 73 | self.__parse_additional_include_directories, 74 | 'VFFortranCompilerTool_Diagnostics': self.__parse_diagnostics, 75 | 'VFFortranCompilerTool_WarnDeclarations': self.__parse_concrete_diagnostics, 76 | 'VFFortranCompilerTool_WarnUnusedVariables': self.__parse_concrete_diagnostics, 77 | 'VFFortranCompilerTool_WarnIgnoreLOC': self.__parse_concrete_diagnostics, 78 | 'VFFortranCompilerTool_WarnTruncateSource': self.__parse_concrete_diagnostics, 79 | 'VFFortranCompilerTool_WarnInterfaces': self.__parse_concrete_diagnostics, 80 | 'VFFortranCompilerTool_WarnUnalignedData': self.__parse_concrete_diagnostics, 81 | 'VFFortranCompilerTool_WarnUncalled': self.__parse_concrete_diagnostics, 82 | 'VFFortranCompilerTool_SuppressUsageMessages': self.__parse_concrete_diagnostics, 83 | 'VFFortranCompilerTool_RuntimeChecks': self.__parse_runtime_checks, 84 | 'VFFortranCompilerTool_NullPointerCheck': self.__parse_concrete_runtime_checks, 85 | 'VFFortranCompilerTool_BoundsCheck': self.__parse_concrete_runtime_checks, 86 | 'VFFortranCompilerTool_UninitializedVariablesCheck': 87 | self.__parse_concrete_runtime_checks, 88 | 'VFFortranCompilerTool_DescriptorDataTypeCheck': self.__parse_concrete_runtime_checks, 89 | 'VFFortranCompilerTool_DescriptorDataSizeCheck': self.__parse_concrete_runtime_checks, 90 | 'VFFortranCompilerTool_ArgTempCreatedCheck': self.__parse_concrete_runtime_checks, 91 | 'VFFortranCompilerTool_StackFrameCheck': self.__parse_concrete_runtime_checks, 92 | 'VFFortranCompilerTool_ModulePath': context.variables.set_module_dir, 93 | # 'VFFortranCompilerTool_ObjectFile': self.do_nothing_attr_stub, 94 | # 'VFFortranCompilerTool_AssemblerListingLocation': self.do_nothing_attr_stub, 95 | # 'VFFortranCompilerTool_PdbFile': self.do_nothing_attr_stub, 96 | 'VFFortranCompilerTool_ParallelizerDiagLevel': self.do_nothing_attr_stub, # obsolete? 97 | 'VFFortranCompilerTool_VectorizerDiagLevel': self.do_nothing_attr_stub, # obsolete? 98 | 'VFLinkerTool_OutputFile': context.variables.set_output_file, 99 | 'VFLibrarianTool_OutputFile': context.variables.set_output_file, 100 | 'VFLinkerTool_ImportLibrary': context.variables.set_import_library, 101 | 'VFLinkerTool_ProgramDatabaseFile': context.variables.set_program_database_file, 102 | 'VFLibrarianTool_ImportLibrary': context.variables.set_import_library, 103 | 'VFLinkerTool_AdditionalDependencies': 104 | context.dependencies.set_target_additional_dependencies, 105 | 'VFLibrarianTool_AdditionalDependencies': 106 | context.dependencies.set_target_additional_dependencies, 107 | 'VFLinkerTool_AdditionalLibraryDirectories': 108 | context.dependencies.set_target_additional_library_directories, 109 | 'VFLibrarianTool_AdditionalLibraryDirectories': 110 | context.dependencies.set_target_additional_library_directories, 111 | 'VFResourceCompilerTool_PreprocessorDefinitions': 112 | self.__parse_preprocessor_definitions, 113 | 'VFResourceCompilerTool_Culture': 114 | self.do_nothing_attr_stub, 115 | # 'VFResourceCompilerTool_ResourceOutputFileName': 116 | # self.do_nothing_attr_stub, 117 | 'VFPreBuildEventTool_ExcludedFromBuild': self.do_nothing_attr_stub, 118 | 'VFPreBuildEventTool_CommandLine': 119 | context.dependencies.set_target_pre_build_events, 120 | 'VFPreBuildEventTool_Description': self.do_nothing_attr_stub, 121 | 'VFPreLinkEventTool_ExcludedFromBuild': self.do_nothing_attr_stub, 122 | 'VFPreLinkEventTool_CommandLine': 123 | context.dependencies.set_target_pre_link_events, 124 | 'VFPreLinkEventTool_Description': self.do_nothing_attr_stub, 125 | 'VFPostBuildEventTool_ExcludedFromBuild': self.do_nothing_attr_stub, 126 | 'VFPostBuildEventTool_CommandLine': 127 | context.dependencies.set_target_post_build_events, 128 | 'VFPostBuildEventTool_Description': self.do_nothing_attr_stub, 129 | 'VFCustomBuildTool_ExcludedFromBuild': self.do_nothing_attr_stub, 130 | 'VFCustomBuildTool_CommandLine': 131 | context.dependencies.set_custom_build_event, 132 | 'VFCustomBuildTool_Description': self.do_nothing_attr_stub, 133 | 'VFCustomBuildTool_Outputs': self.do_nothing_attr_stub, 134 | 'File_RelativePath': self.__parse_file_relative_path, 135 | 'Filter_Name': self.do_nothing_attr_stub, 136 | 'Filter_Filter': self.do_nothing_attr_stub, 137 | }) 138 | return attributes_handlers 139 | 140 | def parse(self, context): 141 | context.xml_data = get_xml_data(context, context.vcxproj_path) 142 | tree = context.xml_data['tree'] 143 | root = tree.getroot() 144 | context.current_node = root 145 | self._parse_nodes(context, root) 146 | context.current_node = None 147 | context.files.apply_files_to_context(context) 148 | context.dependencies.set_target_references(context) 149 | 150 | def __parse_configurations(self, context, configurations_node): 151 | self._parse_nodes(context, configurations_node) 152 | 153 | def __parse_configuration(self, context, configuration_node): 154 | 155 | context.flags.prepare_context_for_flags(context) 156 | self._parse_nodes(context, configuration_node) 157 | context.flags.apply_flags_to_context(context) 158 | 159 | def __parse_configuration_name(self, context, attr_name, configuration_name, node): 160 | del attr_name 161 | 162 | cmake_setting = make_cmake_configuration(context, configuration_name) 163 | setting = tuple(cmake_setting.split('|')) 164 | 165 | if setting not in context.configurations_to_parse: 166 | context.current_setting = (None, None) 167 | raise StopParseException() 168 | 169 | context.current_setting = setting 170 | self.common_diagnostics_value = None 171 | self.common_runtime_checks_value = None 172 | context.utils.init_context_current_setting(context) 173 | self.reset_current_setting_after_parsing_node(node) 174 | 175 | @staticmethod 176 | def __parse_target_name(context, attr_name, target_name_value, node): 177 | del attr_name, node 178 | 179 | context.variables.set_target_name(context, target_name_value) 180 | 181 | @staticmethod 182 | def __parse_configuration_intermediate_dir(context, attr_name, intermediate_dir_value, node): 183 | pass 184 | 185 | @staticmethod 186 | def __parse_configuration_type(context, attr_name, configuration_type_value, node): 187 | del attr_name, node 188 | 189 | configuration_type_value = configuration_type_value.replace('type', '') 190 | context.settings[context.current_setting]['target_type'] = configuration_type_value 191 | 192 | @staticmethod 193 | def __parse_tool_name(context, attr_name, tool_name_value, tool_node): 194 | del attr_name, context 195 | 196 | if tool_name_value in ['VFMidlTool', 'VFManifestTool']: 197 | raise StopParseException() 198 | tool_node.tag = tool_name_value 199 | 200 | @staticmethod 201 | def __parse_preprocessor_definitions(context, flag_name, preprocessor_definitions_value, node): 202 | del flag_name, node 203 | for define in preprocessor_definitions_value.split(';'): 204 | define = define.strip() 205 | context.settings[context.current_setting]['defines'].append(define) 206 | 207 | @staticmethod 208 | def __parse_additional_include_directories( 209 | context, 210 | flag_name, 211 | additional_include_directories_value, 212 | node 213 | ): 214 | del flag_name, node 215 | 216 | context.dependencies.set_additional_include_directories( 217 | additional_include_directories_value, 218 | context.current_setting, 219 | context 220 | ) 221 | 222 | def __parse_diagnostics(self, context, attr_name, attr_value, node): 223 | context.flags.set_flag(context, attr_name, attr_value, node) 224 | self.common_diagnostics_value = attr_value 225 | 226 | def __parse_concrete_diagnostics(self, context, attr_name, attr_value, node): 227 | if self.common_diagnostics_value is None: 228 | context.flags.set_flag(context, attr_name, attr_value, node) 229 | 230 | def __parse_runtime_checks(self, context, attr_name, attr_value, node): 231 | context.flags.set_flag(context, attr_name, attr_value, node) 232 | self.common_runtime_checks_value = attr_value 233 | 234 | def __parse_concrete_runtime_checks(self, context, attr_name, attr_value, node): 235 | if self.common_runtime_checks_value is None: 236 | context.flags.set_flag(context, attr_name, attr_value, node) 237 | 238 | def __parse_files(self, context, filter_node): 239 | context.files.init_file_lists_for_include_paths(context) 240 | self._parse_nodes(context, filter_node) 241 | 242 | def __parse_file_relative_path(self, context, attr_name, attr_value, file_node): 243 | del attr_name, attr_value 244 | 245 | source_group = '' 246 | parent = file_node.getparent() 247 | if Parser.strip_namespace(parent.tag) == 'Filter': 248 | source_group = parent.attrib['Name'] 249 | file_context = context.files.add_file_from_node( 250 | context, 251 | files_container=context.sources, 252 | file_node=file_node, 253 | file_node_attr='RelativePath', 254 | source_group=source_group 255 | ) 256 | if file_context is not None: 257 | self._parse_nodes(file_context, file_node) 258 | context.warnings_count += file_context.warnings_count 259 | 260 | def __parse_filter(self, context, filter_node): 261 | self._parse_nodes(context, filter_node) 262 | -------------------------------------------------------------------------------- /cmake_converter/data_converter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (c) 2016-2020: 5 | # Matthieu Estrada, ttamalfor@gmail.com 6 | # Pavel Liavonau, liavonlida@gmail.com 7 | # 8 | # This file is part of (CMakeConverter). 9 | # 10 | # (CMakeConverter) is free software: you can redistribute it and/or modify 11 | # it under the terms of the GNU Affero General Public License as published by 12 | # the Free Software Foundation, either version 3 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # (CMakeConverter) is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU Affero General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU Affero General Public License 21 | # along with (CMakeConverter). If not, see . 22 | 23 | """ 24 | DataConverter 25 | ============= 26 | Manage conversion of data into CMake 27 | """ 28 | 29 | import os 30 | from collections import OrderedDict 31 | from multiprocessing import Pool 32 | import shutil 33 | import copy 34 | 35 | from cmake_converter.data_files import get_cmake_lists 36 | from cmake_converter.utils import message 37 | from cmake_converter.context import Context 38 | 39 | 40 | class DataConverter: 41 | """ 42 | Base class for converters 43 | """ 44 | 45 | @staticmethod 46 | def collect_data(context): 47 | """ 48 | Collect data for converter. 49 | 50 | """ 51 | 52 | message(context, 'Collecting data for project {}'.format(context.vcxproj_path), '') 53 | context.parser.parse(context) 54 | 55 | context.files.find_cmake_target_languages(context) 56 | 57 | def verify_data(self, context): 58 | """ Verify procedure after gathering information from source project """ 59 | self.__verify_target_types(context) 60 | if 'vcxproj' in context.vcxproj_path: 61 | self.__verify_common_language_runtime_target_property(context) 62 | return self.__verify_configurations_to_parse(context) 63 | 64 | @staticmethod 65 | def __verify_target_types(context): 66 | target_types = set() 67 | for setting in context.settings: 68 | if None in setting: 69 | continue 70 | target_types.add(context.settings[setting]['target_type']) 71 | 72 | if len(target_types) > 1: 73 | message( 74 | context, 75 | 'Target has more than one output binary type. CMake does not support it!', 76 | 'warn' 77 | ) 78 | 79 | @staticmethod 80 | def __verify_common_language_runtime_target_property(context): 81 | target_clr = set() 82 | for setting in context.settings: 83 | if None in setting: 84 | continue 85 | if context.settings[setting]['COMMON_LANGUAGE_RUNTIME']: 86 | target_clr.add(context.settings[setting]['COMMON_LANGUAGE_RUNTIME'][0]) 87 | 88 | if len(target_clr) > 1: 89 | message( 90 | context, 91 | 'Target has different types of common language runtime. CMake does not support it!', 92 | 'warn' 93 | ) 94 | 95 | @staticmethod 96 | def __verify_configurations_to_parse(context): 97 | absent_settings = set() 98 | for setting in context.configurations_to_parse: 99 | if setting not in context.settings: 100 | absent_settings.add(setting) 101 | 102 | if len(absent_settings) > 0: 103 | context.configurations_to_parse -= absent_settings 104 | message( 105 | context, 106 | 'There are absent settings at {}: {}\n' 107 | 'skipping conversion. Add lost settings or fix mapping of settings at solution' 108 | .format(context.vcxproj_path, absent_settings), 109 | 'error' 110 | ) 111 | return False 112 | return True 113 | 114 | def merge_data_settings(self, context): 115 | """ 116 | Merge common settings found among configuration settings (reduce copy-paste) 117 | 118 | :param context: 119 | :return: 120 | """ 121 | 122 | for key in context.utils.lists_of_settings_to_merge(): 123 | lists_of_items_to_merge = {} 124 | set_of_items = {} 125 | 126 | # get intersection pass 127 | for sln_setting in context.sln_configurations_map: 128 | mapped_setting = context.sln_configurations_map[sln_setting] 129 | mapped_arch = sln_setting[1] 130 | if mapped_arch is not None and mapped_arch not in lists_of_items_to_merge: 131 | lists_of_items_to_merge[mapped_arch] = OrderedDict() 132 | if (None, mapped_arch) not in context.settings: 133 | context.current_setting = (None, mapped_arch) 134 | context.utils.init_context_current_setting(context) 135 | 136 | if key not in context.settings[mapped_setting] \ 137 | or mapped_setting[0] is None: 138 | continue 139 | settings_list = context.settings[mapped_setting][key] 140 | if not lists_of_items_to_merge[mapped_arch]: # first pass 141 | set_of_items[mapped_arch] = set(settings_list) 142 | 143 | lists_of_items_to_merge[mapped_arch][sln_setting] = settings_list 144 | set_of_items[mapped_arch] = set_of_items[mapped_arch].intersection( 145 | set(context.settings[mapped_setting][key]) 146 | ) 147 | 148 | self.__remove_common_settings_from_context( 149 | context, 150 | lists_of_items_to_merge, 151 | set_of_items, 152 | key 153 | ) 154 | 155 | merged_order_lists = self.__get_order_of_common_settings(lists_of_items_to_merge) 156 | 157 | merged_settings = self.__get_common_ordered_settings( 158 | merged_order_lists, 159 | set_of_items 160 | ) 161 | 162 | for arch, merged_setting in merged_settings.items(): 163 | context.settings[(None, arch)][key] = merged_setting 164 | context.sln_configurations_map[(None, arch)] = (None, arch) 165 | 166 | if context.file_contexts is not None: 167 | for file in context.file_contexts: 168 | self.merge_data_settings(context.file_contexts[file]) 169 | 170 | def __remove_common_settings_from_context( 171 | self, context, lists_of_items_to_merge, set_of_items, key 172 | ): 173 | """ Removing common settings from configurations """ 174 | for arch in lists_of_items_to_merge: 175 | for sln_setting in lists_of_items_to_merge[arch]: 176 | result_settings_list = [] 177 | for element in lists_of_items_to_merge[arch][sln_setting]: 178 | if element not in set_of_items[arch]: 179 | result_settings_list.append(element) 180 | self.__update_settings_at_context( 181 | context, sln_setting, key, result_settings_list 182 | ) 183 | 184 | @staticmethod 185 | def __update_settings_at_context(context, sln_setting, key, settings_to_set): 186 | if sln_setting not in context.settings: 187 | context.settings[sln_setting] = \ 188 | copy.deepcopy(context.settings[context.sln_configurations_map[sln_setting]]) 189 | context.sln_configurations_map[sln_setting] = sln_setting 190 | context.settings[sln_setting][key] = settings_to_set 191 | 192 | @staticmethod 193 | def __get_order_of_common_settings(lists_of_items_to_merge_arch): 194 | merged_order_lists = {} 195 | for arch in lists_of_items_to_merge_arch: 196 | lists_of_items_to_merge = lists_of_items_to_merge_arch[arch] 197 | merged_order_lists[arch] = [] 198 | i = 0 199 | while True: 200 | out_of_bounds = 0 201 | for setting in lists_of_items_to_merge: 202 | settings_list = lists_of_items_to_merge[setting] 203 | if i < len(settings_list): 204 | merged_order_lists[arch].append(settings_list[i]) 205 | else: 206 | out_of_bounds += 1 207 | 208 | if out_of_bounds == len(lists_of_items_to_merge): 209 | break 210 | i += 1 211 | 212 | return merged_order_lists 213 | 214 | @staticmethod 215 | def __get_common_ordered_settings(merged_order_list_arch, set_of_items): 216 | common_ordered_lists = {} 217 | for arch in merged_order_list_arch: 218 | merged_order_list = merged_order_list_arch[arch] 219 | common_ordered_lists[arch] = [] 220 | for element in merged_order_list: 221 | if element in set_of_items[arch]: 222 | common_ordered_lists[arch].append(element) 223 | set_of_items[arch].remove(element) 224 | if not set_of_items: 225 | break 226 | 227 | return common_ordered_lists 228 | 229 | @staticmethod 230 | def write_data(context, cmake_file): 231 | """ 232 | Write data defined in converter. 233 | 234 | :param context: converter context 235 | :type context: Context 236 | :param cmake_file: CMakeLists IO wrapper 237 | :type cmake_file: _io.TextIOWrapper 238 | """ 239 | 240 | context.writer.write_target_cmake_lists(context, cmake_file) 241 | 242 | def convert_project(self, context, xml_project_path, cmake_lists_destination_path): 243 | """ 244 | Method template for data collecting and writing 245 | 246 | """ 247 | # Initialize Context of DataConverter 248 | if not context.init(xml_project_path, cmake_lists_destination_path): 249 | return False 250 | 251 | message(context, 'Conversion started: Project {}'.format(context.project_name), 'done') 252 | self.collect_data(context) 253 | if not self.verify_data(context): 254 | return False 255 | self.merge_data_settings(context) 256 | if context.dry: 257 | return True 258 | 259 | message(context, f'Writing data for project {context.vcxproj_path}', '') 260 | if os.path.exists(os.path.join(context.cmake, 'CMakeLists.txt')): 261 | for cmake_file in get_cmake_lists(context, context.cmake, 'a'): 262 | cmake_file.write('\n' * 26) 263 | self.write_data(context, cmake_file) 264 | else: 265 | for cmake_file in get_cmake_lists(context, context.cmake): 266 | self.write_data(context, cmake_file) 267 | 268 | warnings = '' 269 | if context.warnings_count > 0: 270 | warnings = ' ({} warnings)'.format(context.warnings_count) 271 | message( 272 | context, 273 | 'Conversion done : Project {}{}'.format(context.project_name, warnings), 'done' 274 | ) 275 | 276 | return True 277 | 278 | def run_conversion(self, subdirectory_targets_data): 279 | """ Routine that converts projects located at the same directory """ 280 | results = [] 281 | for target_data in subdirectory_targets_data: 282 | target_context = target_data['target_context'] 283 | number = target_context.target_number 284 | message(target_context, '------ Starting {} -------'.format(number), '') 285 | converted = self.convert_project( 286 | target_context, 287 | target_data['target_abs'], 288 | target_data['subdirectory'], 289 | ) 290 | message(target_context, '------ Exiting {} -------'.format(number), '') 291 | 292 | if not converted: 293 | continue 294 | 295 | target_context = target_data['target_context'] 296 | # Can't return context as a result due PicklingError 297 | results.append( 298 | { 299 | 'cmake': target_context.cmake, 300 | 'target_name': target_context.project_name, 301 | 'project_languages': target_context.project_languages, 302 | 'target_windows_ver': target_context.target_windows_version, 303 | 'warnings_count': target_context.warnings_count 304 | } 305 | ) 306 | return results 307 | 308 | def do_conversion(self, project_context, input_data_for_converter): 309 | """ Executes conversion with given projects input data """ 310 | input_converter_data_list = [] 311 | for subdirectory in input_data_for_converter: 312 | input_converter_data_list.append(input_data_for_converter[subdirectory]) 313 | 314 | results = [] 315 | if project_context.jobs > 1: 316 | with Pool(project_context.jobs) as pool: 317 | results = pool.map(self.run_conversion, input_converter_data_list) 318 | else: # do in main thread 319 | for data_for_converter in input_converter_data_list: 320 | results.append(self.run_conversion(data_for_converter)) 321 | 322 | return results 323 | 324 | @staticmethod 325 | def copy_cmake_utils(cmake_lists_path): 326 | """ Copy necessary util files into CMake folder """ 327 | utils_path = os.path.join(cmake_lists_path, 'CMake') 328 | if not os.path.exists(utils_path): 329 | os.makedirs(utils_path) 330 | src_dir = os.path.dirname(os.path.abspath(__file__)) 331 | shutil.copyfile(os.path.join(src_dir, 'utils.cmake'), utils_path + '/Utils.cmake') 332 | -------------------------------------------------------------------------------- /test/datatest/external/g3log.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {57C865C2-C5CC-48D0-8AF6-FCC941C7DADF} 23 | Win32Proj 24 | core 25 | 10.0.16299.0 26 | 27 | 28 | 29 | StaticLibrary 30 | true 31 | v141 32 | Unicode 33 | 34 | 35 | StaticLibrary 36 | true 37 | v141 38 | Unicode 39 | 40 | 41 | StaticLibrary 42 | false 43 | v141 44 | true 45 | Unicode 46 | 47 | 48 | StaticLibrary 49 | false 50 | v141 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | true 72 | $(ProjectDir)..\..\..\build\vc2017_x86d\bin\ 73 | $(ProjectName) 74 | $(ProjectName)\$(Platform)\$(Configuration)\ 75 | NativeRecommendedRules.ruleset 76 | 77 | 78 | $(ProjectName) 79 | true 80 | $(ProjectDir)..\..\..\build\vc2017_x64d\bin\ 81 | $(ProjectName)\$(Platform)\$(Configuration)\ 82 | NativeRecommendedRules.ruleset 83 | 84 | 85 | false 86 | $(ProjectDir)..\..\..\build\vc2017_x86\bin\ 87 | $(ProjectName)\$(Platform)\$(Configuration)\ 88 | NativeRecommendedRules.ruleset 89 | 90 | 91 | false 92 | $(ProjectDir)..\..\..\build\vc2017_x64\bin\ 93 | $(ProjectName)\$(Platform)\$(Configuration)\ 94 | NativeRecommendedRules.ruleset 95 | 96 | 97 | 98 | 99 | 100 | Level4 101 | Disabled 102 | _CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_WINDOWS;_USRDLL;CORE_EXPORTS;%(PreprocessorDefinitions) 103 | false 104 | MultiThreadedDebugDLL 105 | 106 | 107 | 108 | 109 | Windows 110 | true 111 | dbghelp.lib;pathcch.lib;%(AdditionalDependencies) 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | Level4 122 | Disabled 123 | _CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_WINDOWS;_USRDLL;CORE_EXPORTS;%(PreprocessorDefinitions) 124 | false 125 | 126 | 127 | 128 | 129 | Windows 130 | true 131 | dbghelp.lib;pathcch.lib;%(AdditionalDependencies) 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | Level4 141 | 142 | 143 | MaxSpeed 144 | true 145 | true 146 | _CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_WINDOWS;_USRDLL;CORE_EXPORTS;%(PreprocessorDefinitions) 147 | false 148 | MultiThreadedDLL 149 | 150 | 151 | 152 | 153 | Windows 154 | true 155 | true 156 | true 157 | dbghelp.lib;pathcch.lib;%(AdditionalDependencies) 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | Level4 166 | 167 | 168 | MaxSpeed 169 | true 170 | true 171 | _CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_WINDOWS;_USRDLL;CORE_EXPORTS;%(PreprocessorDefinitions) 172 | false 173 | 174 | 175 | 176 | 177 | Windows 178 | true 179 | true 180 | true 181 | dbghelp.lib;pathcch.lib;%(AdditionalDependencies) 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 238 | 239 | 240 | 241 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | --------------------------------------------------------------------------------