Merge branch 'feature/idf_tools_dir_user_facing' into 'master'

IDF Tools directory: user facing changes

Closes IDF-61

See merge request idf/esp-idf!4808
This commit is contained in:
Ivan Grokhotkov 2019-07-02 01:47:16 +08:00
commit bca4afb466
45 changed files with 3246 additions and 522 deletions

7
.gitignore vendored
View file

@ -58,13 +58,6 @@ TEST_LOGS
coverage.info
coverage_report/
# Windows tools installer build
tools/windows/tool_setup/.*
tools/windows/tool_setup/input
tools/windows/tool_setup/dl
tools/windows/tool_setup/keys
tools/windows/tool_setup/Output
test_multi_heap_host
# VS Code Settings

View file

@ -9,8 +9,7 @@
if [ -z ${IDF_PATH} ]; then
echo "IDF_PATH must be set before including this script."
else
IDF_ADD_PATHS_EXTRAS=
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/esptool_py/esptool"
IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool"
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/espcoredump"
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/partition_table/"
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/tools/"

View file

@ -1,75 +1,3 @@
Add IDF_PATH & idf.py PATH to User Profile (CMake)
==================================================
:orphan:
:link_to_translation:`zh_CN:[中文]`
.. include:: ../cmake-warning.rst
To use the CMake-based build system and the idf.py tool, two modifications need to be made to system environment variables:
- ``IDF_PATH`` needs to be set to the path of the directory containing ESP-IDF.
- System ``PATH`` variable to include the directory containing the ``idf.py`` tool (part of ESP-IDF).
To preserve setting of these variables between system restarts, add them to the user profile by following the instructions below.
.. note:: If using an IDE, you can optionally set these environment variables in your IDE's project environment rather than from the command line as described below.
.. note:: If you don't ever use the command line ``idf.py`` tool, but run cmake directly or via an IDE, then it is not necessary to set the ``PATH`` variable - only ``IDF_PATH``. However it can be useful to set both.
.. note:: If you only ever use the command line ``idf.py`` tool, and never use cmake directly or via an IDE, then it is not necessary to set the ``IDF_PATH`` variable - ``idf.py`` will detect the directory it is contained within and set ``IDF_PATH`` appropriately if it is missing.
.. _add-paths-to-profile-windows-cmake:
Windows
-------
To edit Environment Variables on Windows 10, search for "Edit Environment Variables" under the Start menu.
On earlier Windows versions, open the System Control Panel then choose "Advanced" and look for the Environment Variables button.
You can set these environment variables for all users, or only for the current user, depending on whether other users of your computer will be using ESP-IDF.
- Click ``New...`` to add a new system variable named ``IDF_PATH``. Set the path to directory containing ESP-IDF, for example ``C:\Users\user-name\esp\esp-idf``.
- Locate the ``Path`` environment variable and double-click to edit it. Append the following to the end: ``;%IDF_PATH%\tools``. This will allow you to run ``idf.py`` and other tools from Windows Command Prompt.
If you got here from :ref:`get-started-setup-path-cmake`, while installing s/w for ESP32 development, then you can continue with :ref:`get-started-get-packages-cmake`.
.. _add-idf_path-to-profile-linux-macos-cmake:
Linux and MacOS
---------------
Set up ``IDF_PATH`` and add ``idf.py`` to the PATH by adding the following two lines to your ``~/.profile`` file::
export IDF_PATH=~/esp/esp-idf
export PATH="$IDF_PATH/tools:$PATH"
.. note::
``~/.profile`` means a file named ``.profile`` in your user's home directory (which is abbreviated ``~`` in the shell).
Log off and log in back to make this change effective.
.. note::
Not all shells use ``.profile``. If you have ``/bin/bash`` and ``.bash_profile`` exists then update this file instead. For ``zsh``, update ``.zprofile``. Other shells may use other profile files (consult the shell's documentation).
Run the following command to check if ``IDF_PATH`` is set::
printenv IDF_PATH
The path previously entered in ``~/.profile`` file (or set manually) should be printed out.
To verify ``idf.py`` is now on the ``PATH``, you can run the following::
which idf.py
A path like ``${IDF_PATH}/tools/idf.py`` should be printed.
If you do not like to have ``IDF_PATH`` or ``PATH`` modifications set, you can enter it manually in terminal window on each restart or logout::
export IDF_PATH=~/esp/esp-idf
export PATH="$IDF_PATH/tools:$PATH"
If you got here from :ref:`get-started-setup-path-cmake`, while installing s/w for ESP32 development, then you can continue with :ref:`get-started-get-packages-cmake`.
.. Remove this file when the Chinese translation of CMake getting started guide is updated

View file

@ -78,10 +78,10 @@ This is a detailed roadmap to walk you through the installation process.
Setting up Development Environment
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* :ref:`get-started-setup-toolchain-cmake` for :doc:`Windows <windows-setup>`, :doc:`Linux <linux-setup>` or :doc:`MacOS <macos-setup>`
* :ref:`get-started-get-prerequisites-cmake` for :doc:`Windows <windows-setup>`, :doc:`Linux <linux-setup>` or :doc:`macOS <macos-setup>`
* :ref:`get-started-get-esp-idf-cmake`
* :ref:`get-started-setup-path-cmake`
* :ref:`get-started-get-packages-cmake`
* :ref:`get-started-set-up-tools-cmake`
* :ref:`get-started-set-up-env-cmake`
Creating Your First Project
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -94,60 +94,40 @@ Creating Your First Project
* :ref:`get-started-build-monitor-cmake`
.. _get-started-setup-toolchain-cmake:
.. _get-started-get-prerequisites-cmake:
Step 1. Set up the Toolchain
============================
Step 1. Install prerequisites
=============================
The toolchain is a set of programs for compiling code and building applications.
The quickest way to start development with ESP32 is by installing a prebuilt toolchain. Pick up your OS below and follow the provided instructions.
Some tools need to be installed on the computer before proceeding to the next steps. Follow the links below for the instructions for your OS:
.. toctree::
:hidden:
Windows <windows-setup>
Linux <linux-setup>
MacOS <macos-setup>
+-------------------+-------------------+-------------------+
| |windows-logo| | |linux-logo| | |macos-logo| |
+-------------------+-------------------+-------------------+
| `Windows`_ | `Linux`_ | `Mac OS`_ |
+-------------------+-------------------+-------------------+
.. |windows-logo| image:: ../../_static/windows-logo.png
:target: ../get-started-cmake/windows-setup.html
.. |linux-logo| image:: ../../_static/linux-logo.png
:target: ../get-started-cmake/linux-setup.html
.. |macos-logo| image:: ../../_static/macos-logo.png
:target: ../get-started-cmake/macos-setup.html
.. _Windows: ../get-started-cmake/windows-setup.html
.. _Linux: ../get-started-cmake/linux-setup.html
.. _Mac OS: ../get-started-cmake/macos-setup.html
.. note::
This guide uses the directory ``~/esp`` on Linux and macOS or ``%userprofile%\esp`` on Windows as an installation folder for ESP-IDF. You can use any directory, but you will need to adjust paths for the commands respectively. Keep in mind that ESP-IDF does not support spaces in paths.
Depending on your experience and preferences, you may want to customize your environment instead of using a prebuilt toolchain. To set up the system your own way go to Section :ref:`get-started-customized-setup-cmake`.
Linux <linux-setup>
macOS <macos-setup>
* :doc:`windows-setup`
* :doc:`linux-setup`
* :doc:`macos-setup`
.. _get-started-get-esp-idf-cmake:
Step 2. Get ESP-IDF
===================
Besides the toolchain, you also need ESP32-specific API (software libraries and source code). They are provided by Espressif in `ESP-IDF repository <https://github.com/espressif/esp-idf>`_.
To build applications for the ESP32, you need the software libraries provided by Espressif in `ESP-IDF repository <https://github.com/espressif/esp-idf>`_.
Get ESP-IDF in accordance with your operating system.
To get ESP-IDF, navigate to your installation directory and clone the repository with ``git clone``.
Linux and MacOS
.. note::
This guide uses the directory ``~/esp`` on Linux and macOS or ``%userprofile%\esp`` on Windows as an installation folder for ESP-IDF. You can use any directory, but you will need to adjust paths for the commands respectively. Keep in mind that ESP-IDF does not support spaces in paths.
Linux and macOS
~~~~~~~~~~~~~~~
Open Terminal, and run the following commands:
@ -161,60 +141,76 @@ Consult :doc:`/versions` for information about which ESP-IDF version to use in a
Windows
~~~~~~~
.. note::
Previous versions of ESP-IDF used the **MSYS2 bash terminal** command line. The current cmake-based build system can run in the regular **Windows Command Prompt** which is used here.
If you use a bash-based terminal or PowerShell, please note that some command syntax will be different to what is shown below.
Open Command Prompt and run the following commands:
.. include:: /_build/inc/git-clone-windows.inc
ESP-IDF will be downloaded into ``%userprofile%\esp\esp-idf``.
In addition to installing the tools, :ref:`get-started-cmake-windows-tools-installer` for Windows introduced in Step 1 can also download a copy of ESP-IDF.
Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation.
.. include:: /_build/inc/git-clone-notes.inc
If you wish to download ESP-IDF without the help of ESP-IDF Tools Installer, refer to these :ref:`instructions <get-esp-idf-windows-command-line-cmake>`.
.. note::
.. _get-started-set-up-tools-cmake:
Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules::
Step 3. Set up the tools
========================
cd esp-idf
git submodule update --init
Aside from the ESP-IDF, you also need to install the tools used by ESP-IDF, such as the compiler, debugger, Python packages, etc.
Windows
~~~~~~~
.. _get-started-setup-path-cmake:
:ref:`get-started-cmake-windows-tools-installer` for Windows introduced in Step 1 installs all the required tools.
Step 3. Set Environment Variables
=================================
If you want to install the tools without the help of ESP-IDF Tools Installer, open the Command Prompt and follow these steps:
Set the following environment variables on your computer, so that projects can be built:
.. code-block:: batch
- Create ``IDF_PATH`` and assign it the path to the ESP-IDF directory.
- Add to ``PATH`` the path to the ``tools`` directory inside the ``IDF_PATH`` directory.
cd %userprofile%\esp\esp-idf
install.bat
These variables can be set temporarily (per session) or permanently. Please follow the instructions specific to :ref:`Windows <add-paths-to-profile-windows-cmake>` , :ref:`Linux and MacOS <add-idf_path-to-profile-linux-macos-cmake>` in Section :doc:`add-idf_path-to-profile`.
Linux and macOS
~~~~~~~~~~~~~~~
.. code-block:: bash
.. _get-started-get-packages-cmake:
cd ~/esp/esp-idf
./install.sh
Step 4. Install the Required Python Packages
============================================
Customizing the tools installation path
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The python packages required by ESP-IDF are located in ``IDF_PATH/requirements.txt``. You can install them by running::
The scripts introduced in this step install compilation tools required by ESP-IDF inside the user home directory: ``$HOME/.espressif`` on Linux and macOS, ``%USERPROFILE%\.espressif`` on Windows. If you wish to install the tools into a different directory, set the environment variable ``IDF_TOOLS_PATH`` before running the installation scripts. Make sure that your user has sufficient permissions to read and write this path.
python -m pip install --user -r $IDF_PATH/requirements.txt
If changing the ``IDF_TOOLS_PATH``, make sure it is set to the same value every time the ``install.bat``/``install.sh`` and ``export.bat``/``export.sh`` scripts are executed.
.. note::
.. _get-started-set-up-env-cmake:
Please check the version of the Python interpreter that you will be using with ESP-IDF. For this, run
the command ``python --version`` and depending on the result, you might want to use ``python2``, ``python2.7``
or similar instead of just ``python``, e.g.::
Step 4. Set up the environment variables
========================================
python2.7 -m pip install --user -r $IDF_PATH/requirements.txt
The installed tools are not yet added to the PATH environment variable. To make the tools usable from the command line, some environment variables must be set. ESP-IDF provides another script which does that.
Windows
~~~~~~~
:ref:`get-started-cmake-windows-tools-installer` for Windows creates an "ESP-IDF Command Prompt" shortcut in the Start Menu. This shortcut opens the Command Prompt and sets up all the required environment variables. You can open this shortcut and proceed to the next step.
Alternatively, if you want to use ESP-IDF in an existing Command Prompt window, you can run:
.. code-block:: batch
%userprofile%\esp\esp-idf\export.bat
Linux and macOS
~~~~~~~~~~~~~~~
In the terminal where you are going to use ESP-IDF, run:
.. code-block:: bash
. $HOME/esp/esp-idf/export.sh
Note the space between the leading dot and the path!
You can also automate this step, making ESP-IDF tools available in every terminal, by adding this line to your ``.profile`` or ``.bash_profile`` script.
.. _get-started-start-project-cmake:
@ -225,7 +221,7 @@ Now you are ready to prepare your application for ESP32. You can start with :exa
Copy :example:`get-started/hello_world` to ``~/esp`` directory:
Linux and MacOS
Linux and macOS
~~~~~~~~~~~~~~~
.. code-block:: bash
@ -247,7 +243,7 @@ It is also possible to build examples in-place, without copying them first.
.. important::
The esp-idf build system does not support spaces in the paths to either esp-idf or to projects.
The ESP-IDF build system does not support spaces in the paths to either ESP-IDF or to projects.
.. _get-started-connect-cmake:
@ -276,7 +272,7 @@ Step 7. Configure
Navigate to your ``hello_world`` directory from :ref:`get-started-start-project-cmake` and run the project configuration utility ``menuconfig``.
Linux and MacOS
Linux and macOS
~~~~~~~~~~~~~~~
.. code-block:: bash
@ -294,12 +290,6 @@ Windows
cd %userprofile%\esp\hello_world
idf.py menuconfig
The Python 2.7 installer will try to configure Windows to associate ``.py`` files with Python 2. If a separately installed program, such as Visual Studio Python Tools, has created an association with a different version of Python, then running ``idf.py`` may not work (it opens the file in Visual Studio instead). You can either run ``C:\Python27\python idf.py`` each time instead, or change the association that Windows uses for ``.py`` files.
.. note::
If you get an error ``idf.py not found``, make sure that the ``PATH`` environment variable was set correctly in :ref:`get-started-setup-path-cmake`. If there is no ``idf.py`` in ``tools``, make sure you have the correct branch for the CMake preview as shown under :ref:`get-started-get-esp-idf-cmake`.
If the previous steps have been done correctly, the following menu appears:
.. figure:: ../../_static/project-configuration.png
@ -480,17 +470,18 @@ Updating ESP-IDF
You should update ESP-IDF from time to time, as newer versions fix bugs and provide new features. The simplest way to do the update is to delete the existing ``esp-idf`` folder and clone it again, as if performing the initial installation described in :ref:`get-started-get-esp-idf-cmake`.
If downloading to a new path, remember to :doc:`add-idf_path-to-profile` so that the toolchain scripts can find ESP-IDF in its release specific location.
Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using <updating>`.
After updating ESP-IDF, execute ``install.sh`` (``install.bat`` on Windows) again, in case the new ESP-IDF version requires different versions of tools. See instructions at :ref:`get-started-set-up-tools-cmake`.
Once the new tools are installed, update the environment using ``export.sh`` (``export.bat`` on Windows). See instructions at :ref:`get-started-set-up-env-cmake`.
Related Documents
=================
.. toctree::
:maxdepth: 1
add-idf_path-to-profile
establish-serial-connection
eclipse-setup
../api-guides/tools/idf-monitor

View file

@ -68,7 +68,7 @@ Build the toolchain::
./ct-ng build
chmod -R u+w builds/xtensa-esp32-elf
Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. Follow `instructions for standard setup <setup-linux-toolchain-add-it-to-path-cmake>`_ to add the toolchain to your ``PATH``.
Toolchain will be built in ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``. To use it, you need to add ``~/esp/crosstool-NG/builds/xtensa-esp32-elf/bin`` to ``PATH`` environment variable.
Next Steps

View file

@ -1,6 +1,6 @@
*********************************************
Standard Setup of Toolchain for Linux (CMake)
*********************************************
***********************************************
Installation of Prerequisites for Linux (CMake)
***********************************************
:link_to_translation:`zh_CN:[中文]`
@ -26,61 +26,9 @@ To compile with ESP-IDF you need to get the following packages:
.. note::
CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake".
Toolchain Setup
Additional Tips
===============
.. include:: /_build/inc/download-links.inc
ESP32 toolchain for Linux is available for download from Espressif website:
- for 64-bit Linux:
|download_link_linux64|
- for 32-bit Linux:
|download_link_linux32|
1. Download this file, then extract it in ``~/esp`` directory:
- for 64-bit Linux:
.. include:: /_build/inc/unpack-code-linux64.inc
- for 32-bit Linux:
.. include:: /_build/inc/unpack-code-linux32.inc
.. _setup-linux-toolchain-add-it-to-path-cmake:
2. The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory.
To use it, you will need to update your ``PATH`` environment variable in ``~/.profile`` file. To make ``xtensa-esp32-elf`` available for all terminal sessions, add the following line to your ``~/.profile`` file::
export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"
Alternatively, you may create an alias for the above command. This way you can get the toolchain only when you need it. To do this, add different line to your ``~/.profile`` file::
alias get_esp32='export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"'
Then when you need the toolchain you can type ``get_esp32`` on the command line and the toolchain will be added to your ``PATH``.
.. note::
If you have ``/bin/bash`` set as login shell, and both ``.bash_profile`` and ``.profile`` exist, then update ``.bash_profile`` instead.
3. Log off and log in back to make the ``.profile`` changes effective. Run the following command to verify if ``PATH`` is correctly set::
printenv PATH
You are looking for similar result containing toolchain's path at the beginning of displayed string::
$ printenv PATH
/home/user-name/esp/xtensa-esp32-elf/bin:/home/user-name/bin:/home/user-name/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
Instead of ``/home/user-name`` there should be a home path specific to your installation.
Permission issues /dev/ttyUSB0
------------------------------

View file

@ -79,7 +79,7 @@ Build the toolchain::
./ct-ng build
chmod -R u+w builds/xtensa-esp32-elf
Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``. Follow :ref:`instructions for standard setup <setup-macos-toolchain-add-it-to-path-cmake>` to add the toolchain to your ``PATH``.
Toolchain will be built in ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``. To use it, you need to add ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf/bin`` to ``PATH`` environment variable.
Next Steps

View file

@ -1,6 +1,6 @@
**********************************************
Standard Setup of Toolchain for Mac OS (CMake)
**********************************************
***********************************************
Installation of Prerequisites for macOS (CMake)
***********************************************
:link_to_translation:`zh_CN:[中文]`
@ -9,7 +9,7 @@ Standard Setup of Toolchain for Mac OS (CMake)
Install Prerequisites
=====================
ESP-IDF will use the version of Python installed by default on Mac OS.
ESP-IDF will use the version of Python installed by default on macOS.
- install pip::
@ -29,7 +29,7 @@ ESP-IDF will use the version of Python installed by default on Mac OS.
sudo port install cmake ninja
- Otherwise, consult the CMake_ and Ninja_ home pages for Mac OS installation downloads.
- Otherwise, consult the CMake_ and Ninja_ home pages for macOS installation downloads.
- It is strongly recommended to also install ccache_ for faster builds. If you have HomeBrew_, this can be done via ``brew install ccache`` or ``sudo port install ccache`` on MacPorts_.
@ -38,39 +38,7 @@ ESP-IDF will use the version of Python installed by default on Mac OS.
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
Then you will need to install the XCode command line tools to continue. You can install these by running ``xcode-select --install``.
Toolchain Setup
===============
.. include:: /_build/inc/download-links.inc
ESP32 toolchain for macOS is available for download from Espressif website:
|download_link_osx|
Download this file, then extract it in ``~/esp`` directory:
.. include:: /_build/inc/unpack-code-osx.inc
.. _setup-macos-toolchain-add-it-to-path-cmake:
The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory.
To use it, you will need to update your ``PATH`` environment variable in ``~/.profile`` file. To make ``xtensa-esp32-elf`` available for all terminal sessions, add the following line to your ``~/.profile`` file::
export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH
Alternatively, you may create an alias for the above command. This way you can get the toolchain only when you need it. To do this, add different line to your ``~/.profile`` file::
alias get_esp32="export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH"
Then when you need the toolchain you can type ``get_esp32`` on the command line and the toolchain will be added to your ``PATH``.
Log off and log in back to make the ``.profile`` changes effective. Run the following command to verify if ``PATH`` is correctly set::
printenv PATH
Then you will need to install the XCode command line tools to continue. You can install these by running ``xcode-select --install``.
Next Steps
==========

View file

@ -6,7 +6,7 @@ Customized Setup of Toolchain (CMake)
:link_to_translation:`zh_CN:[中文]`
Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-setup-toolchain-cmake`) you may build the toolchain yourself.
Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-set-up-tools-cmake`) you may build the toolchain yourself.
If you can't think of a reason why you need to build it yourself, then probably it's better to stick with the binary version. However, here are some of the reasons why you might want to compile it from source:

View file

@ -1,6 +1,6 @@
********************************************
Setup Windows Toolchain from Scratch (CMake)
********************************************
**********************************
Windows Setup from Scratch (CMake)
**********************************
:link_to_translation:`zh_CN:[中文]`
@ -10,10 +10,38 @@ This is a step-by-step alternative to running the :doc:`ESP-IDF Tools Installer
To quickly setup the toolchain and other tools in standard way, using the ESP-IDF Tools installer, proceed to section :doc:`windows-setup`.
.. note::
The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment.
.. _get-esp-idf-windows-command-line-cmake:
Get ESP-IDF
===========
.. note::
Previous versions of ESP-IDF used the **MSYS2 bash terminal** command line. The current cmake-based build system can run in the regular **Windows Command Prompt** which is used here.
If you use a bash-based terminal or PowerShell, please note that some command syntax will be different to what is shown below.
Open Command Prompt and run the following commands:
.. include:: /_build/inc/git-clone-windows.inc
ESP-IDF will be downloaded into ``%userprofile%\esp\esp-idf``.
Consult :doc:`/versions` for information about which ESP-IDF version to use in a given situation.
.. include:: /_build/inc/git-clone-notes.inc
.. note::
Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules::
cd esp-idf
git submodule update --init
Tools
=====
@ -90,4 +118,5 @@ To carry on with development environment setup, proceed to :ref:`get-started-get
.. _ninja: https://ninja-build.org/
.. _Python: https://www.python.org/downloads/windows/
.. _MSYS2: https://msys2.github.io/
.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/

View file

@ -0,0 +1,31 @@
*********************************
Updating ESP-IDF tools on Windows
*********************************
.. _get-started-cmake-install_bat-windows:
Install ESP-IDF tools using ``install.bat``
===========================================
From the Windows Command Prompt, change to the directory where ESP-IDF is installed. Then run::
install.bat
This will download and install the tools necessary to use ESP-IDF. If the specific version of the tool is already installed, no action will be taken.
The tools are downloaded and installed into a directory specified during ESP-IDF Tools Installer process. By default, this is ``C:\Users\username\.espressif``.
.. _get-started-cmake-export_bat-windows:
Add ESP-IDF tools to PATH using ``export.bat``
==============================================
ESP-IDF tools installer creates a Start menu shortcut for "ESP-IDF Command Prompt". This shortcut opens a Command Prompt window where all the tools are already available.
In some cases, you may want to work with ESP-IDF in a Command Prompt window which wasn't started using that shortcut. If this is the case, follow the instructions below to add ESP-IDF tools to PATH.
In the command prompt where you need to use ESP-IDF, change to the directory where ESP-IDF is installed, then execute ``export.bat``::
cd %userprofile%\esp\esp-idf
export.bat
When this is done, the tools will be available in this command prompt.

View file

@ -1,6 +1,6 @@
***********************************************
Standard Setup of Toolchain for Windows (CMake)
***********************************************
*************************************************
Installation of Prerequisites for Windows (CMake)
*************************************************
:link_to_translation:`zh_CN:[中文]`
@ -12,46 +12,43 @@ Standard Setup of Toolchain for Windows (CMake)
Introduction
============
ESP-IDF requires some prerequisite tools to be installed so you can build firmware for the ESP32. The prerequisite tools include Git, a cross-compiler and the CMake build tool. We'll go over each one in this document.
ESP-IDF requires some prerequisite tools to be installed so you can build firmware for the ESP32. The prerequisite tools include Python, Git, cross-compilers, menuconfig tool, CMake and Ninja build tools.
For this Getting Started we're going to use a command prompt, but after ESP-IDF is installed you can use :doc:`Eclipse <eclipse-setup>` or another graphical IDE with CMake support instead.
For this Getting Started we're going to use the Command Prompt, but after ESP-IDF is installed you can use :doc:`Eclipse <eclipse-setup>` or another graphical IDE with CMake support instead.
.. note::
The GNU Make based build system requires the MSYS2_ Unix compatibility environment on Windows. The CMake-based build system does not require this environment.
.. _get-started-cmake-windows-tools-installer:
ESP-IDF Tools Installer
=======================
The easiest way to install ESP-IDF's prerequisites is to download the ESP-IDF Tools installer from this URL:
https://dl.espressif.com/dl/esp-idf-tools-setup-1.2.exe
https://dl.espressif.com/dl/esp-idf-tools-setup-2.0.exe
The installer will automatically install the ESP32 Xtensa gcc toolchain, Ninja_ build tool, and a configuration tool called mconf-idf_. The installer can also download and run installers for CMake_ and Python_ 2.7 if these are not already installed on the computer.
The installer includes the cross-compilers, OpenOCD, cmake_ and Ninja_ build tool, and a configuration tool called mconf-idf_. The installer can also download and run installers for Python_ 3.7 and `Git For Windows`_ if they are not already installed on the computer.
By default, the installer updates the Windows ``Path`` environment variable so all of these tools can be run from anywhere. If you disable this option, you will need to configure the environment where you are using ESP-IDF (terminal or chosen IDE) with the correct paths.
The installer also offers to download one of the ESP-IDF release versions.
Note that this installer is for the ESP-IDF Tools package, it doesn't include ESP-IDF itself.
Using the Command Prompt
========================
Installing Git
==============
For the remaining Getting Started steps, we're going to use the Windows Command Prompt.
The ESP-IDF tools installer does not install Git. By default, the getting started guide assumes you will be using Git on the command line. You can download and install a command line Git for Windows (along with the "Git Bash" terminal) from `Git For Windows`_.
ESP-IDF Tools Installer creates a shortcut in the Start menu to launch the ESP-IDF Command Prompt. This shortcut launches the Command Prompt (cmd.exe) and runs ``export.bat`` script to set up the environment variables (``PATH``, ``IDF_PATH`` and others). Inside this command prompt, all the installed tools are available.
If you prefer to use a different graphical Git client, then you can install one such as `Github Desktop`. You will need to translate the Git commands in the Getting Started guide for use with your chosen Git client.
Note that this shortcut is specific to the ESP-IDF directory selected in the ESP-IDF Tools Installer. If you have multiple ESP-IDF directories on the computer (for example, to work with different versions of ESP-IDF), you have two options to use them:
Using a Terminal
================
1. Create a copy of the shortcut created by the ESP-IDF Tools Installer, and change the working directory of the new shortcut to the ESP-IDF directory you wish to use.
For the remaining Getting Started steps, we're going to use a terminal command prompt. It doesn't matter which command prompt you use:
- You can use the built-in Windows Command Prompt, under the Start menu. All Windows command line instructions in this documentation are "batch" commands for use with the Windows Command Prompt.
- You can use the "Git Bash" terminal which is part of `Git for Windows`_. This uses the same "bash" command prompt syntax as is given for Mac OS or Linux. You can find it in the Start menu once installed.
- If you have MSYS2_ installed (maybe from a previous ESP-IDF version), then you can also use the MSYS terminal.
2. Alternatively, run ``cmd.exe``, then change to the ESP-IDF directory you wish to use, and run ``export.bat``. Note that unlike the previous option, this way requires Python and Git to be present in ``PATH``. If you get errors related to Python or Git not being found, use the first option.
Next Steps
==========
To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`.
If the ESP-IDF Tools Installer has finished successfully, then the development environment setup is complete. Proceed directly to :ref:`get-started-start-project-cmake`.
Related Documents
=================
@ -62,7 +59,7 @@ For advanced users who want to customize the install process:
:maxdepth: 1
windows-setup-scratch
windows-setup-update
.. _MSYS2: https://msys2.github.io/
.. _cmake: https://cmake.org/download/

View file

@ -0,0 +1,3 @@
:orphan:
.. Remove this file when the Chinese translation of CMake getting started guide is updated

70
export.bat Normal file
View file

@ -0,0 +1,70 @@
@echo off
if defined MSYSTEM (
echo This .bat file is for Windows CMD.EXE shell only. When using MSYS, run:
echo . ./export.sh.
goto :eof
)
:: Infer IDF_PATH from script location
set IDF_PATH=%~dp0
set IDF_PATH=%IDF_PATH:~0,-1%
set IDF_TOOLS_PY_PATH=%IDF_PATH%\tools\idf_tools.py
set IDF_TOOLS_JSON_PATH=%IDF_PATH%\tools\tools.json
set IDF_TOOLS_EXPORT_CMD=%IDF_PATH%\export.bat
set IDF_TOOLS_INSTALL_CMD=%IDF_PATH%\install.bat
echo Setting IDF_PATH: %IDF_PATH%
echo.
set "OLD_PATH=%PATH%"
echo Adding ESP-IDF tools to PATH...
:: Export tool paths and environment variables.
:: It is possible to do this without a temporary file (running idf_tools.py from for /r command),
:: but that way it is impossible to get the exit code of idf_tools.py.
set "IDF_TOOLS_EXPORTS_FILE=%TEMP%\idf_export_vars.tmp"
python.exe %IDF_PATH%\tools\idf_tools.py export --format key-value >"%IDF_TOOLS_EXPORTS_FILE%"
if %errorlevel% neq 0 goto :end
for /f "usebackq tokens=1,2 eol=# delims==" %%a in ("%IDF_TOOLS_EXPORTS_FILE%") do (
call set "%%a=%%b"
)
:: This removes OLD_PATH substring from PATH, leaving only the paths which have been added,
:: and prints semicolon-delimited components of the path on separate lines
call set PATH_ADDITIONS=%%PATH:%OLD_PATH%=%%
if "%PATH_ADDITIONS%"=="" call :print_nothing_added
if not "%PATH_ADDITIONS%"=="" echo %PATH_ADDITIONS:;=&echo. %
echo Checking if Python packages are up to date...
python.exe %IDF_PATH%\tools\check_python_dependencies.py
if %errorlevel% neq 0 goto :end
echo.
echo Done! You can now compile ESP-IDF projects.
echo Go to the project directory and run:
echo.
echo idf.py build
echo.
goto :end
:print_nothing_added
echo No directories added to PATH:
echo.
echo %PATH%
echo.
goto :eof
:end
:: Clean up
if not "%IDF_TOOLS_EXPORTS_FILE%"=="" (
del "%IDF_TOOLS_EXPORTS_FILE%" 1>nul 2>nul
)
set IDF_TOOLS_EXPORTS_FILE=
set IDF_TOOLS_EXPORT_CMD=
set IDF_TOOLS_INSTALL_CMD=
set IDF_TOOLS_PY_PATH=
set IDF_TOOLS_JSON_PATH=
set OLD_PATH=
set PATH_ADDITIONS=

82
export.sh Normal file
View file

@ -0,0 +1,82 @@
# This script should be sourced, not executed.
function idf_export_main() {
# The file doesn't have executable permissions, so this shouldn't really happen.
# Doing this in case someone tries to chmod +x it and execute...
if [[ -n "${BASH_SOURCE}" && ( "${BASH_SOURCE[0]}" == "${0}" ) ]]; then
echo "This script should be sourced, not executed:"
echo ". ${BASH_SOURCE[0]}"
return 1
fi
if [[ -z "${IDF_PATH}" ]]
then
# If using bash, try to guess IDF_PATH from script location
if [[ -n "${BASH_SOURCE}" ]]
then
script_name="$(readlink -f $BASH_SOURCE)"
export IDF_PATH="$(dirname ${script_name})"
else
echo "IDF_PATH must be set before sourcing this script"
return 1
fi
fi
old_path=$PATH
echo "Adding ESP-IDF tools to PATH..."
# Call idf_tools.py to export tool paths
export IDF_TOOLS_EXPORT_CMD=${IDF_PATH}/export.sh
export IDF_TOOLS_INSTALL_CMD=${IDF_PATH}/install.sh
idf_exports=$(${IDF_PATH}/tools/idf_tools.py export) || return 1
eval "${idf_exports}"
echo "Checking if Python packages are up to date..."
python ${IDF_PATH}/tools/check_python_dependencies.py || return 1
# Allow calling some IDF python tools without specifying the full path
# ${IDF_PATH}/tools is already added by 'idf_tools.py export'
IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool"
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/espcoredump"
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/partition_table/"
export PATH="${IDF_ADD_PATHS_EXTRAS}:${PATH}"
if [[ -n "$BASH" ]]
then
path_prefix=${PATH%%${old_path}}
paths="${path_prefix//:/ }"
if [ -n "${paths}" ]; then
echo "Added the following directories to PATH:"
else
echo "All paths are already set."
fi
for path_entry in ${paths}
do
echo " ${path_entry}"
done
else
echo "Updated PATH variable:"
echo " ${PATH}"
fi
# Clean up
unset old_path
unset paths
unset path_prefix
unset path_entry
unset IDF_ADD_PATHS_EXTRAS
unset idf_exports
# Not unsetting IDF_PYTHON_ENV_PATH, it can be used by IDF build system
# to check whether we are using a private Python environment
echo "Done! You can now compile ESP-IDF projects."
echo "Go to the project directory and run:"
echo ""
echo " idf.py build"
echo ""
}
idf_export_main
unset idf_export_main

19
install.bat Normal file
View file

@ -0,0 +1,19 @@
@echo off
if defined MSYSTEM (
echo This .bat file is for Windows CMD.EXE shell only. When using MSYS, run:
echo ./install.sh.
goto end
)
:: Infer IDF_PATH from script location
set IDF_PATH=%~dp0
set IDF_PATH=%IDF_PATH:~0,-1%
echo Installing ESP-IDF tools
python.exe %IDF_PATH%\tools\idf_tools.py install
echo Setting up Python environment
python.exe %IDF_PATH%\tools\idf_tools.py install-python-env
echo All done! You can now run:
echo export.bat
:: Clean up

18
install.sh Executable file
View file

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -e
set -u
export IDF_PATH=$(cd $(dirname $0); pwd)
echo "Installing ESP-IDF tools"
${IDF_PATH}/tools/idf_tools.py install
echo "Installing Python environment and packages"
${IDF_PATH}/tools/idf_tools.py install-python-env
basedir="$(dirname $0)"
echo "All done! You can now run:"
echo ""
echo " . ${basedir}/export.sh"
echo ""

View file

@ -26,6 +26,7 @@ examples/storage/parttool/parttool_example.sh
examples/system/ota/otatool/get_running_partition.py
examples/system/ota/otatool/otatool_example.py
examples/system/ota/otatool/otatool_example.sh
install.sh
tools/check_kconfigs.py
tools/check_python_dependencies.py
tools/ci/apply_bot_filter.py

View file

@ -559,10 +559,10 @@ class IDFTool(object):
expected_size = download_obj.size
file_size, file_sha256 = get_file_size_sha256(local_path)
if file_size != expected_size:
warn('file size mismatch for {0}'.format(local_path))
warn('file size mismatch for {}, expected {}, got {}'.format(local_path, expected_size, file_size))
return False
if file_sha256 != expected_sha256:
warn('hash mismatch for {0}'.format(local_path))
warn('hash mismatch for {}, expected {}, got {}'.format(local_path, expected_sha256, file_sha256))
return False
return True

View file

@ -243,17 +243,17 @@
"version_regex": "mconf-idf version mconf-([a-z0-9.-]+)-win32",
"versions": [
{
"name": "v4.6.0.0-idf-20190313",
"name": "v4.6.0.0-idf-20190628",
"status": "recommended",
"win32": {
"sha256": "051bef09c782bc31b737b047808d1b6588b0965101b77dc979af9139773c4b4f",
"size": 826167,
"url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190313/mconf-v4.6.0.0-idf-20190313-win32.zip"
"sha256": "1b8f17f48740ab669c13bd89136e8cc92efe0cd29872f0d6c44148902a2dc40c",
"size": 826114,
"url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190628/mconf-v4.6.0.0-idf-20190628-win32.zip"
},
"win64": {
"sha256": "051bef09c782bc31b737b047808d1b6588b0965101b77dc979af9139773c4b4f",
"size": 826167,
"url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190313/mconf-v4.6.0.0-idf-20190313-win32.zip"
"sha256": "1b8f17f48740ab669c13bd89136e8cc92efe0cd29872f0d6c44148902a2dc40c",
"size": 826114,
"url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190628/mconf-v4.6.0.0-idf-20190628-win32.zip"
}
}
]
@ -306,6 +306,49 @@
}
]
},
{
"description": "IDF wrapper tool for Windows",
"export_paths": [
[
""
]
],
"export_vars": {},
"info_url": "https://github.com/espressif/esp-idf/tree/master/tools/windows/idf_exe",
"install": "never",
"license": "Apache-2.0",
"name": "idf-exe",
"platform_overrides": [
{
"install": "always",
"platforms": [
"win32",
"win64"
]
}
],
"version_cmd": [
"idf.py.exe",
"-v"
],
"version_regex": "([0-9.]+)",
"versions": [
{
"name": "1.0",
"status": "recommended",
"win32": {
"sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748",
"size": 11289,
"url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip"
},
"win64": {
"sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748",
"size": 11289,
"url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip"
}
}
]
},
{
"description": "Ccache (compiler cache)",
"export_paths": [

View file

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.5)
project(idfexe)
set(VERSION 1.0)
set(ARCHIVE_NAME idf-exe-v${VERSION}.zip)
add_executable(idf idf_main.c)
set_target_properties(idf PROPERTIES C_STANDARD 99)
target_link_libraries(idf "-lshlwapi")
if(CMAKE_BUILD_TYPE STREQUAL Release)
add_custom_command(TARGET idf
POST_BUILD
COMMAND ${CMAKE_STRIP} idf.exe)
endif()
add_custom_target(dist ALL DEPENDS idf)
add_custom_command(
TARGET dist
POST_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -E copy "${CMAKE_CURRENT_BINARY_DIR}/idf.exe" "${CMAKE_CURRENT_BINARY_DIR}/idf.py.exe"
COMMAND ${CMAKE_COMMAND} ARGS -E tar cfv ${ARCHIVE_NAME} --format=zip
"${CMAKE_CURRENT_BINARY_DIR}/idf.py.exe"
)

View file

@ -0,0 +1,34 @@
# IDF wrapper tool (idf.py.exe)
This tools helps invoke idf.py in Windows CMD shell.
In Windows CMD shell, python scripts can be executed directly (by typing their name) if `.py` extension is associated with Python. The issue with such association is that it is incompatible with virtual environments. That is, if `.py` extension is associated with a global (or user-specific) copy of `python.exe`, then the virtual environment will not be used when running the script. [Python Launcher](https://www.python.org/dev/peps/pep-0397/) solves this issue, but it is installed by default only with Python 3.6 and newer. In addition to that, the user may choose not to install Python Launcher (for example, to keep `.py` files associated with an editor).
Hence, `idf.py.exe` is introduced. It is a simple program which forwards the command line arguments to `idf.py`. That is,
```
idf.py args...
```
has the same effect as:
```
python.exe %IDF_PATH%\tools\idf.py args...
```
`python.exe` location is determined using the default search rules, which include searching the directories in `%PATH%`. Standard I/O streams are forwarded between `idf.py.exe` and `python.exe` processes. The exit code of `idf.py.exe` is the same as the exit code of `python.exe` process.
For compatibility with `idf_tools.py`, a flag to obtain the version of `idf.py.exe` is provided: `idf.py.exe -v` or `idf.py.exe --version`. Note that this flag only works when `idf.py.exe` is started by the full name (with `.exe` extension). Running `idf.py -v` results in same behavior as `python idf.py -v`, that is `-v` argument is propagated to the Python script.
## Building
On Linux/Mac, install mingw-w64 toolchain (`i686-w64-mingw32-gcc`). Then build `idf.py.exe` using CMake:
```
mkdir -p build
cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-i686-w64-mingw32.cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
```
On Windows, it is also possible to build using Visual Studio, with CMake support installed.

View file

@ -0,0 +1,111 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at",
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
#include <windows.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <stdarg.h>
#define LINESIZE 1024
#define VERSION "1.0"
static void fail(LPCSTR message, ...) __attribute__((noreturn));
static void fail(LPCSTR message, ...)
{
DWORD written;
char msg[LINESIZE];
va_list args = NULL;
va_start(args, message);
StringCchVPrintfA(msg, sizeof(msg), message, args);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), message, lstrlen(msg), &written, NULL);
ExitProcess(1);
}
int main(int argc, LPTSTR argv[])
{
/* Print the version of this wrapper tool, but only if invoked as "idf.exe".
* "idf -v" will invoke idf.py as expected.
*/
LPCTSTR cmdname = PathFindFileName(argv[0]);
int cmdname_length = strlen(cmdname);
if (argc == 2 &&
cmdname_length > 4 &&
StrCmp(cmdname + cmdname_length - 4, TEXT(".exe")) == 0 &&
(StrCmp(argv[1], TEXT("--version")) == 0 ||
StrCmp(argv[1], TEXT("-v")) == 0)) {
LPCSTR msg = VERSION "\n";
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msg, lstrlen(msg), NULL, NULL);
return 0;
}
LPCTSTR idfpy_script_name = TEXT("idf.py");
/* Get IDF_PATH */
TCHAR idf_path[LINESIZE] = {};
if (GetEnvironmentVariable(TEXT("IDF_PATH"), idf_path, sizeof(idf_path)) == 0) {
DWORD err = GetLastError();
if (err == ERROR_ENVVAR_NOT_FOUND) {
fail("IDF_PATH environment variable needs to be set to use this tool\n");
} else {
fail("Unknown error (%u)\n", err);
}
}
/* Prepare the command line: python.exe %IDF_PATH%\\tools\idf.py <rest of the args> */
TCHAR cmdline[LINESIZE] = {};
StringCchCat(cmdline, sizeof(cmdline), TEXT("python.exe "));
StringCchCat(cmdline, sizeof(cmdline), idf_path);
StringCchCat(cmdline, sizeof(cmdline), TEXT("\\tools\\"));
StringCchCat(cmdline, sizeof(cmdline), idfpy_script_name);
StringCchCat(cmdline, sizeof(cmdline), TEXT(" "));
for (int i = 1; i < argc; ++i) {
StringCchCat(cmdline, sizeof(cmdline), argv[i]);
StringCchCat(cmdline, sizeof(cmdline), TEXT(" "));
}
SetEnvironmentVariable(TEXT("IDF_PY_PROGRAM_NAME"), idfpy_script_name);
/* Reuse the standard streams of this process */
STARTUPINFO start_info = {
.cb = sizeof(STARTUPINFO),
.hStdError = GetStdHandle(STD_ERROR_HANDLE),
.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE),
.hStdInput = GetStdHandle(STD_INPUT_HANDLE),
.dwFlags = STARTF_USESTDHANDLES
};
/* Run the child process */
PROCESS_INFORMATION child_process;
if (!CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &start_info, &child_process)) {
DWORD err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND) {
fail("Can not find Python\n");
} else {
fail("Unknown error (%u)\n", err);
}
}
/* Wait for it to complete */
WaitForSingleObject(child_process.hProcess, INFINITE);
/* Return with the exit code of the child process */
DWORD exitcode;
if (!GetExitCodeProcess(child_process.hProcess, &exitcode)) {
fail("Couldn't get the exit code (%u)\n", GetLastError());
}
return exitcode;
}

View file

@ -0,0 +1,7 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86)
set(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

6
tools/windows/tool_setup/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
Output
cmdlinerunner/build
dist
unzip
keys
idf_versions.txt

View file

@ -0,0 +1,39 @@
# ESP-IDF Tools Installer for Windows
This directory contains source files required to build the tools installer for Windows.
The installer is built using [Inno Setup](http://www.jrsoftware.org/isinfo.php). At the time of writing, the installer can be built with Inno Setup version 6.0.2.
The main source file of the installer is `idf_tools_setup.iss`. PascalScript code is split into multiple `*.iss.inc` files.
Some functionality of the installer depends on additional programs:
* [Inno Download Plugin](https://bitbucket.org/mitrich_k/inno-download-plugin) — used to download additional files during the installation.
* [7-zip](https://www.7-zip.org) — used to extract downloaded IDF archives.
* [cmdlinerunner](cmdlinerunner/cmdlinerunner.c) — a helper DLL used to run external command line programs from the installer, capture live console output, and get the exit code.
## Steps required to build the installer
* Build cmdlinerunner DLL.
- On Linux/Mac, install mingw-w64 toolchain (`i686-w64-mingw32-gcc`). Then build the DLL using CMake:
```
mkdir -p cmdlinerunner/build
cd cmdlinerunner/build
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-i686-w64-mingw32.cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
```
This will produce `cmdlinerunner.dll` in the build directory.
- On Windows, it is possible to build using Visual Studio, with CMake support installed. By default, VS produces build artifacts in some hard to find directory. You can adjust this in CmakeSettings.json file generated by VS.
* Download 7zip.exe [("standalone console version")](https://www.7-zip.org/download.html) and put it into `unzip` directory (to get `unzip/7za.exe`).
* Download [idf_versions.txt](https://dl.espressif.com/dl/esp-idf/idf_versions.txt) and place it into the current directory. The installer will use it as a fallback, if it can not download idf_versions.txt at run time.
* Create the `dist` directory and populate it with the tools which should be bundled with the installer. At the moment the easiest way to obtain it is to use `install.sh`/`install.bat` in IDF, and then copy the contents of `$HOME/.espressif/dist` directory. If the directory is empty, the installer should still work, and the tools will be downloaded during the installation.
* Build the installer using Inno Setup Compiler: `ISCC.exe idf_tools_setup.iss`.
* Obtain the signing keys, then sign `Output/esp-idf-tools-setup-unsigned.exe`.

View file

@ -0,0 +1,247 @@
var
ChoicePagePrepare: array of TNotifyEvent;
ChoicePageSelectionChange: array of TNotifyEvent;
ChoicePageValidate: array of TWizardPageButtonEvent;
ChoicePageMaxTag: Integer;
ChoicePages: array of TInputOptionWizardPage;
procedure ChoicePageOnClickCheck(Sender: TObject);
var
ListBox: TNewCheckListBox;
Id: Integer;
begin
ListBox := TNewCheckListBox(Sender);
Id := Integer(ListBox.Tag);
ChoicePageSelectionChange[Id](ChoicePages[Id]);
end;
function ChoicePageGetInput(Page: TInputOptionWizardPage): TNewEdit;
begin
Result := TNewEdit(Page.FindComponent('ChoicePageInput'));
end;
function ChoicePageGetLabel(Page: TInputOptionWizardPage): TNewStaticText;
begin
Result := TNewStaticText(Page.FindComponent('ChoicePageLabel'));
end;
function ChoicePageGetButton(Page: TInputOptionWizardPage): TNewButton;
begin
Result := TNewButton(Page.FindComponent('ChoicePageBrowseButton'));
end;
procedure ChoicePageSetEditLabel(Page: TInputOptionWizardPage; Caption: String);
var
InputLabel: TNewStaticText;
begin
InputLabel := ChoicePageGetLabel(Page);
InputLabel.Caption := Caption;
end;
function ChoicePageGetInputText(Page: TInputOptionWizardPage): String;
begin
Result := ChoicePageGetInput(Page).Text;
end;
procedure ChoicePageSetInputText(Page: TInputOptionWizardPage; Text: String);
begin
ChoicePageGetInput(Page).Text := Text;
end;
procedure ChoicePageSetInputEnabled(Page: TInputOptionWizardPage; Enabled: Boolean);
begin
ChoicePageGetLabel(Page).Enabled := Enabled;
ChoicePageGetInput(Page).Enabled := Enabled;
ChoicePageGetButton(Page).Enabled := Enabled;
end;
procedure ChoicePageOnBrowseButtonClick(Sender: TObject);
var
Button: TNewButton;
Page: TInputOptionWizardPage;
InputLabel: TNewStaticText;
Input: TNewEdit;
Dir: String;
begin
Button := TNewButton(Sender);
Page := TInputOptionWizardPage(Button.Owner);
Input := ChoicePageGetInput(Page);
InputLabel := ChoicePageGetLabel(Page);
Dir := Input.Text;
if BrowseForFolder(InputLabel.Caption, Dir, True) then
begin
Input.Text := Dir;
end;
end;
<event('CurPageChanged')>
procedure ChoicePageOnCurPageChanged(CurPageID: Integer);
var
i: Integer;
begin
for i := 1 to ChoicePageMaxTag do
begin
if ChoicePages[i].ID = CurPageID then
begin
ChoicePagePrepare[i](ChoicePages[i]);
break;
end;
end;
end;
<event('NextButtonClick')>
function ChoicePageOnNextButtonClick(CurPageID: Integer): Boolean;
var
i: Integer;
begin
Result := True;
for i := 1 to ChoicePageMaxTag do
begin
if ChoicePages[i].ID = CurPageID then
begin
Result := ChoicePageValidate[i](ChoicePages[i]);
break;
end;
end;
end;
<event('InitializeWizard')>
procedure InitChoicePages();
begin
ChoicePages := [ ];
ChoicePagePrepare := [ ];
ChoicePageSelectionChange := [ ];
ChoicePageValidate := [ ];
end;
function FindLinkInText(Text: String): String;
var
Tmp: String;
LinkStartPos, LinkEndPos: Integer;
begin
Result := '';
Tmp := Text;
LinkStartPos := Pos('https://', Tmp);
if LinkStartPos = 0 then exit;
Delete(Tmp, 1, LinkStartPos - 1);
{ Try to find the end of the link }
LinkEndPos := 0
if LinkEndPos = 0 then LinkEndPos := Pos(' ', Tmp);
if LinkEndPos = 0 then LinkEndPos := Pos(',', Tmp);
if LinkEndPos = 0 then LinkEndPos := Pos('.', Tmp);
if LinkEndPos = 0 then LinkEndPos := Length(Tmp);
Delete(Text, LinkEndPos, Length(Tmp));
Log('Found link in "' + Text + '": "' + Tmp + '"');
Result := Tmp;
end;
procedure OnStaticTextClick(Sender: TObject);
var
StaticText: TNewStaticText;
Link: String;
Err: Integer;
begin
StaticText := TNewStaticText(Sender);
Link := FindLinkInText(StaticText.Caption);
if Link = '' then
exit;
ShellExec('open', Link, '', '', SW_SHOWNORMAL, ewNoWait, Err);
end;
procedure MakeStaticTextClickable(StaticText: TNewStaticText);
begin
if FindLinkInText(StaticText.Caption) = '' then
exit;
StaticText.OnClick := @OnStaticTextClick;
StaticText.Cursor := crHand;
end;
function ChoicePageCreate(
const AfterID: Integer;
const Caption, Description, SubCaption, EditCaption: String;
HasDirectoryChooser: Boolean;
Prepare: TNotifyEvent;
SelectionChange: TNotifyEvent;
Validate: TWizardPageButtonEvent): TInputOptionWizardPage;
var
VSpace, Y : Integer;
ChoicePage: TInputOptionWizardPage;
InputLabel: TNewStaticText;
Input: TNewEdit;
Button: TNewButton;
begin
ChoicePageMaxTag := ChoicePageMaxTag + 1;
VSpace := ScaleY(8);
ChoicePage := CreateInputOptionPage(AfterID, Caption,
Description, SubCaption, True, True);
MakeStaticTextClickable(ChoicePage.SubCaptionLabel);
ChoicePage.Tag := ChoicePageMaxTag;
ChoicePage.CheckListBox.OnClickCheck := @ChoicePageOnClickCheck;
ChoicePage.CheckListBox.Tag := ChoicePageMaxTag;
if HasDirectoryChooser then
begin
ChoicePage.CheckListBox.Anchors := [ akLeft, akTop, akRight ];
ChoicePage.CheckListBox.Height := ChoicePage.CheckListBox.Height - ScaleY(60);
Y := ChoicePage.CheckListBox.Top + ChoicePage.CheckListBox.Height + VSpace;
InputLabel := TNewStaticText.Create(ChoicePage);
with InputLabel do
begin
Top := Y;
Anchors := [akTop, akLeft, akRight];
Caption := EditCaption;
AutoSize := True;
Parent := ChoicePage.Surface;
Name := 'ChoicePageLabel';
end;
MakeStaticTextClickable(InputLabel);
Y := Y + InputLabel.Height + VSpace;
Input := TNewEdit.Create(ChoicePage);
with Input do
begin
Top := Y;
Anchors := [akTop, akLeft, akRight];
Parent := ChoicePage.Surface;
Name := 'ChoicePageInput';
Text := '';
end;
Button := TNewButton.Create(ChoicePage);
with Button do
begin
Anchors := [akTop, akRight];
Parent := ChoicePage.Surface;
Width := WizardForm.NextButton.Width;
Height := WizardForm.NextButton.Height;
Top := Y - (Height - Input.Height) / 2;
Left := ChoicePage.SurfaceWidth - Button.Width;
Name := 'ChoicePageBrowseButton';
Caption := SetupMessage(msgButtonWizardBrowse);
OnClick := @ChoicePageOnBrowseButtonClick;
end;
Input.Width := Button.Left - ScaleX(8);
end;
SetArrayLength(ChoicePages, ChoicePageMaxTag+1);
SetArrayLength(ChoicePagePrepare, ChoicePageMaxTag+1);
SetArrayLength(ChoicePageSelectionChange, ChoicePageMaxTag+1);
SetArrayLength(ChoicePageValidate, ChoicePageMaxTag+1);
ChoicePages[ChoicePageMaxTag] := ChoicePage;
ChoicePagePrepare[ChoicePageMaxTag] := Prepare;
ChoicePageSelectionChange[ChoicePageMaxTag] := SelectionChange;
ChoicePageValidate[ChoicePageMaxTag] := Validate;
Result := ChoicePage;
end;

View file

@ -0,0 +1,154 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Progress & log page for command line tools ------------------------------ }
var
CmdlineInstallCancel: Boolean;
{ ------------------------------ Splitting strings into lines and adding them to TStrings ------------------------------ }
procedure StringsAddLine(Dest: TStrings; Line: String; var ReplaceLastLine: Boolean);
begin
if ReplaceLastLine then
begin
Dest.Strings[Dest.Count - 1] := Line;
ReplaceLastLine := False;
end else begin
Dest.Add(Line);
end;
end;
procedure StrSplitAppendToList(Text: String; Dest: TStrings; var LastLine: String);
var
pCR, pLF, Len: Integer;
Tmp: String;
ReplaceLastLine: Boolean;
begin
if Length(LastLine) > 0 then
begin
ReplaceLastLine := True;
Text := LastLine + Text;
end;
repeat
Len := Length(Text);
pLF := Pos(#10, Text);
pCR := Pos(#13, Text);
if (pLF > 0) and ((pCR = 0) or (pLF < pCR) or (pLF = pCR + 1)) then
begin
if pLF < pCR then
Tmp := Copy(Text, 1, pLF - 1)
else
Tmp := Copy(Text, 1, pLF - 2);
StringsAddLine(Dest, Tmp, ReplaceLastLine);
Text := Copy(Text, pLF + 1, Len)
end else begin
if (pCR = Len) or (pCR = 0) then
begin
break;
end;
Text := Copy(Text, pCR + 1, Len)
end;
until (pLF = 0) and (pCR = 0);
LastLine := Text;
if pCR = Len then
begin
Text := Copy(Text, 1, pCR - 1);
end;
if Length(LastLine) > 0 then
begin
StringsAddLine(Dest, Text, ReplaceLastLine);
end;
end;
{ ------------------------------ The actual command line install page ------------------------------ }
procedure OnCmdlineInstallCancel(Sender: TObject);
begin
CmdlineInstallCancel := True;
end;
function DoCmdlineInstall(caption, description, command: String): Boolean;
var
CmdlineInstallPage: TOutputProgressWizardPage;
Res: Integer;
Handle: Longword;
ExitCode: Integer;
LogTextAnsi: AnsiString;
LogText, LeftOver: String;
Memo: TNewMemo;
PrevCancelButtonOnClick: TNotifyEvent;
begin
CmdlineInstallPage := CreateOutputProgressPage('', '')
CmdlineInstallPage.Caption := caption;
CmdlineInstallPage.Description := description;
Memo := TNewMemo.Create(CmdlineInstallPage);
Memo.Top := CmdlineInstallPage.ProgressBar.Top + CmdlineInstallPage.ProgressBar.Height + ScaleY(8);
Memo.Width := CmdlineInstallPage.SurfaceWidth;
Memo.Height := ScaleY(120);
Memo.ScrollBars := ssVertical;
Memo.Parent := CmdlineInstallPage.Surface;
Memo.Lines.Clear();
CmdlineInstallPage.Show();
try
WizardForm.CancelButton.Visible := True;
WizardForm.CancelButton.Enabled := True;
PrevCancelButtonOnClick := WizardForm.CancelButton.OnClick;
WizardForm.CancelButton.OnClick := @OnCmdlineInstallCancel;
CmdlineInstallPage.SetProgress(0, 100);
CmdlineInstallPage.ProgressBar.Style := npbstMarquee;
ExitCode := -1;
Memo.Lines.Append('Running command: ' + command);
Handle := ProcStart(command, ExpandConstant('{tmp}'))
if Handle = 0 then
begin
Log('ProcStart failed');
ExitCode := -2;
end;
while (ExitCode = -1) and not CmdlineInstallCancel do
begin
ExitCode := ProcGetExitCode(Handle);
SetLength(LogTextAnsi, 4096);
Res := ProcGetOutput(Handle, LogTextAnsi, 4096)
if Res > 0 then
begin
SetLength(LogTextAnsi, Res);
LogText := LeftOver + String(LogTextAnsi);
StrSplitAppendToList(LogText, Memo.Lines, LeftOver);
end;
CmdlineInstallPage.SetProgress(0, 100);
Sleep(10);
end;
ProcEnd(Handle);
finally
Log('Done, exit code=' + IntToStr(ExitCode));
Log('--------');
Log(Memo.Lines.Text);
Log('--------');
if CmdlineInstallCancel then
begin
MsgBox('Installation has been cancelled.', mbError, MB_OK);
Result := False;
end else if ExitCode <> 0 then
begin
MsgBox('Installation has failed with exit code ' + IntToStr(ExitCode), mbError, MB_OK);
Result := False;
end else begin
Result := True;
end;
CmdlineInstallPage.Hide;
CmdlineInstallPage.Free;
WizardForm.CancelButton.OnClick := PrevCancelButtonOnClick;
end;
if not Result then
RaiseException('Installation has failed at step: ' + caption);
end;

View file

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.5)
project(cmdlinerunner)
set(CMAKE_EXE_LINKER_FLAGS " -static")
add_library(cmdlinerunner SHARED cmdlinerunner.c)
target_compile_definitions(cmdlinerunner PUBLIC UNICODE _UNICODE)
set_target_properties(cmdlinerunner PROPERTIES PREFIX "")
set_target_properties(cmdlinerunner PROPERTIES C_STANDARD 99)
target_link_libraries(cmdlinerunner "-static-libgcc")

View file

@ -0,0 +1,194 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at",
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
#define CMDLINERUNNER_EXPORTS
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include "cmdlinerunner.h"
#define LINESIZE 1024
#ifdef WITH_DEBUG
#include <stdio.h>
#define DEBUGV(...) do { fprintf(stderr, __VA_ARG__); } while(0)
#else
#define DEBUGV(...)
#endif
struct proc_instance_s {
PROCESS_INFORMATION child_process;
HANDLE pipe_server_handle;
HANDLE pipe_client_handle;
};
#ifdef WITH_DEBUG
static void print_last_error()
{
DWORD dw;
TCHAR errmsg[LINESIZE];
dw = GetLastError();
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
errmsg, sizeof(errmsg) - 1, NULL );
DEBUGV("error %d: %s\n", dw, errmsg);
}
#define PRINT_LAST_ERROR() print_last_error()
#else
#define PRINT_LAST_ERROR()
#endif
static proc_instance_t *proc_instance_allocate()
{
return (proc_instance_t*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(proc_instance_t));
}
static void proc_instance_free(proc_instance_t *instance)
{
if (instance->pipe_server_handle) {
CloseHandle(instance->pipe_server_handle);
}
if (instance->pipe_client_handle) {
CloseHandle(instance->pipe_client_handle);
}
if (instance->child_process.hProcess) {
TerminateProcess(instance->child_process.hProcess, 1);
CloseHandle(instance->child_process.hProcess);
CloseHandle(instance->child_process.hThread);
}
HeapFree(GetProcessHeap(), 0, instance);
}
void proc_end(proc_instance_t *inst)
{
if (inst == NULL) {
return;
}
proc_instance_free(inst);
}
CMDLINERUNNER_API proc_instance_t * proc_start(LPCTSTR cmdline, LPCTSTR workdir)
{
proc_instance_t *inst = proc_instance_allocate();
if (inst == NULL) {
return NULL;
}
SECURITY_ATTRIBUTES sec_attr = {
.nLength = sizeof(SECURITY_ATTRIBUTES),
.bInheritHandle = TRUE,
.lpSecurityDescriptor = NULL
};
LPCTSTR pipename = TEXT("\\\\.\\pipe\\cmdlinerunner_pipe");
inst->pipe_server_handle = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024 * 16, 1024 * 16,
NMPWAIT_WAIT_FOREVER, &sec_attr);
if (inst->pipe_server_handle == INVALID_HANDLE_VALUE) {
DEBUGV("inst->pipe_server_handle == INVALID_HANDLE_VALUE\n");
goto error;
}
inst->pipe_client_handle = CreateFile(pipename, GENERIC_WRITE | GENERIC_READ,
0, &sec_attr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (inst->pipe_client_handle == INVALID_HANDLE_VALUE) {
DEBUGV("inst->pipe_client_handle == INVALID_HANDLE_VALUE\n");
goto error;
}
DWORD new_mode = PIPE_READMODE_BYTE | PIPE_NOWAIT;
if (!SetNamedPipeHandleState(inst->pipe_server_handle, &new_mode, NULL,
NULL)) {
DEBUGV("SetNamedPipeHandleState failed\n");
goto error;
}
if (!SetHandleInformation(inst->pipe_server_handle, HANDLE_FLAG_INHERIT, 0)) {
DEBUGV("SetHandleInformation failed\n");
goto error;
}
if (!SetHandleInformation(inst->pipe_client_handle, HANDLE_FLAG_INHERIT,
HANDLE_FLAG_INHERIT)) {
DEBUGV("SetHandleInformation failed\n");
goto error;
}
STARTUPINFO siStartInfo = {
.cb = sizeof(STARTUPINFO),
.hStdError = inst->pipe_client_handle,
.hStdOutput = inst->pipe_client_handle,
.hStdInput = inst->pipe_client_handle,
.dwFlags = STARTF_USESTDHANDLES
};
size_t workdir_len = 0;
StringCbLength(workdir, STRSAFE_MAX_CCH * sizeof(TCHAR), &workdir_len);
if (workdir_len == 0) {
workdir = NULL;
}
TCHAR cmdline_tmp[LINESIZE];
StringCbCopy(cmdline_tmp, sizeof(cmdline_tmp), cmdline);
if (!CreateProcess(NULL, cmdline_tmp,
NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, workdir, &siStartInfo,
&inst->child_process)) {
DEBUGV("CreateProcess failed\n");
goto error;
}
return inst;
error:
PRINT_LAST_ERROR();
proc_instance_free(inst);
return NULL;
}
int proc_get_exit_code(proc_instance_t *inst)
{
DWORD result;
if (!GetExitCodeProcess(inst->child_process.hProcess, &result)) {
return -2;
}
if (result == STILL_ACTIVE) {
return -1;
}
return (int) result;
}
DWORD proc_get_output(proc_instance_t *inst, LPSTR dest, DWORD sz)
{
DWORD read_bytes;
BOOL res = ReadFile(inst->pipe_server_handle, dest,
sz - 1, &read_bytes, NULL);
if (!res) {
if (GetLastError() == ERROR_NO_DATA) {
return 0;
} else {
PRINT_LAST_ERROR();
return 0;
}
}
dest[read_bytes] = 0;
return read_bytes;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved )
{
return TRUE;
}

View file

@ -0,0 +1,32 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at",
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
#pragma once
#include <windows.h>
struct proc_instance_s;
typedef struct proc_instance_s proc_instance_t;
#ifdef CMDLINERUNNER_EXPORTS
#define CMDLINERUNNER_API __declspec(dllexport)
#else
#define CMDLINERUNNER_API __declspec(dllimport)
#endif
CMDLINERUNNER_API proc_instance_t * proc_start(LPCTSTR cmdline, LPCTSTR workdir);
CMDLINERUNNER_API int proc_get_exit_code(proc_instance_t *inst);
CMDLINERUNNER_API DWORD proc_get_output(proc_instance_t *inst, LPSTR dest, DWORD sz);
CMDLINERUNNER_API void proc_end(proc_instance_t *inst);
CMDLINERUNNER_API BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved );

View file

@ -0,0 +1,7 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86)
set(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

View file

@ -0,0 +1,98 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Find installed copies of Git ------------------------------ }
var
InstalledGitVersions: TStringList;
InstalledGitDisplayNames: TStringList;
InstalledGitExecutables: TStringList;
procedure GitVersionAdd(Version, DisplayName, Executable: String);
begin
Log('Adding Git version=' + Version + ' name='+DisplayName+' executable='+Executable);
InstalledGitVersions.Append(Version);
InstalledGitDisplayNames.Append(DisplayName);
InstalledGitExecutables.Append(Executable);
end;
function GetVersionOfGitExe(Path: String; var Version: String; var ErrStr: String): Boolean;
var
VersionOutputFile: String;
Args: String;
GitVersionAnsi: AnsiString;
GitVersion: String;
GitVersionPrefix: String;
Err: Integer;
begin
VersionOutputFile := ExpandConstant('{tmp}\gitver.txt');
DeleteFile(VersionOutputFile);
Args := '/C "' + Path + '" --version >gitver.txt';
Log('Running ' + Args);
if not ShellExec('', 'cmd.exe', Args,
ExpandConstant('{tmp}'), SW_HIDE, ewWaitUntilTerminated, Err) then
begin
ErrStr := 'Failed to get git version, error=' + IntToStr(err);
Log(ErrStr);
Result := False;
exit;
end;
LoadStringFromFile(VersionOutputFile, GitVersionAnsi);
GitVersion := Trim(String(GitVersionAnsi));
GitVersionPrefix := 'git version ';
if Pos(GitVersionPrefix, GitVersion) <> 1 then
begin
ErrStr := 'Unexpected git version format: ' + GitVersion;
Log(ErrStr);
Result := False;
exit;
end;
Delete(GitVersion, 1, Length(GitVersionPrefix));
Version := GitVersion;
Result := True;
end;
procedure FindGitInPath();
var
Args: String;
GitListFile: String;
GitPaths: TArrayOfString;
GitVersion: String;
ErrStr: String;
Err: Integer;
i: Integer;
begin
GitListFile := ExpandConstant('{tmp}\gitlist.txt');
Args := '/C where git.exe >"' + GitListFile + '"';
if not ShellExec('', 'cmd.exe', Args,
'', SW_HIDE, ewWaitUntilTerminated, Err) then
begin
Log('Failed to find git using "where", error='+IntToStr(Err));
exit;
end;
LoadStringsFromFile(GitListFile, GitPaths);
for i:= 0 to GetArrayLength(GitPaths) - 1 do
begin
Log('Git path: ' + GitPaths[i]);
if not GetVersionOfGitExe(GitPaths[i], GitVersion, ErrStr) then
continue;
Log('Git version: ' + GitVersion);
GitVersionAdd(GitVersion, GitVersion, GitPaths[i]);
end;
end;
procedure FindInstalledGitVersions();
begin
InstalledGitVersions := TStringList.Create();
InstalledGitDisplayNames := TStringList.Create();
InstalledGitExecutables := TStringList.Create();
FindGitInPath();
end;

View file

@ -0,0 +1,194 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Page to select Git ------------------------------ }
#include "git_find_installed.iss.inc"
var
GitPage: TInputOptionWizardPage;
GitPath, GitExecutablePath, GitVersion: String;
GitUseExisting: Boolean;
GitSelectionInstallIndex: Integer;
GitSelectionCustomPathIndex: Integer;
function GetGitPath(Unused: String): String;
begin
Result := GitPath;
end;
function GitInstallRequired(): Boolean;
begin
Result := not GitUseExisting;
end;
function GitVersionSupported(Version: String): Boolean;
var
Major, Minor: Integer;
begin
Result := False;
if not VersionExtractMajorMinor(Version, Major, Minor) then
begin
Log('GitVersionSupported: Could not parse version=' + Version);
exit;
end;
{ Need at least git 2.12 for 'git clone --reference' to work with submodules }
if (Major = 2) and (Minor >= 12) then Result := True;
if (Major > 2) then Result := True;
end;
procedure GitCustomPathUpdateEnabled();
var
Enable: Boolean;
begin
if GitPage.SelectedValueIndex = GitSelectionCustomPathIndex then
Enable := True;
ChoicePageSetInputEnabled(GitPage, Enable);
end;
procedure OnGitPagePrepare(Sender: TObject);
var
Page: TInputOptionWizardPage;
FullName: String;
i, Index, FirstEnabledIndex: Integer;
OfferToInstall: Boolean;
VersionToInstall: String;
VersionSupported: Boolean;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnGitPagePrepare');
if Page.CheckListBox.Items.Count > 0 then
exit;
FindInstalledGitVersions();
VersionToInstall := '{#GitVersion}';
OfferToInstall := True;
FirstEnabledIndex := -1;
for i := 0 to InstalledGitVersions.Count - 1 do
begin
VersionSupported := GitVersionSupported(InstalledGitVersions[i]);
FullName := InstalledGitDisplayNames.Strings[i];
if not VersionSupported then
begin
FullName := FullName + ' (unsupported)';
end;
FullName := FullName + #13#10 + InstalledGitExecutables.Strings[i];
Index := Page.Add(FullName);
if not VersionSupported then
begin
Page.CheckListBox.ItemEnabled[Index] := False;
end else begin
if FirstEnabledIndex < 0 then FirstEnabledIndex := Index;
end;
if InstalledGitVersions[i] = VersionToInstall then
begin
OfferToInstall := False;
end;
end;
if OfferToInstall then
begin
Index := Page.Add('Install Git ' + VersionToInstall);
if FirstEnabledIndex < 0 then FirstEnabledIndex := Index;
GitSelectionInstallIndex := Index;
end;
Index := Page.Add('Custom git.exe location');
if FirstEnabledIndex < 0 then FirstEnabledIndex := Index;
GitSelectionCustomPathIndex := Index;
Page.SelectedValueIndex := FirstEnabledIndex;
GitCustomPathUpdateEnabled();
end;
procedure OnGitSelectionChange(Sender: TObject);
var
Page: TInputOptionWizardPage;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnGitSelectionChange index=' + IntToStr(Page.SelectedValueIndex));
GitCustomPathUpdateEnabled();
end;
function OnGitPageValidate(Sender: TWizardPage): Boolean;
var
Page: TInputOptionWizardPage;
Version, ErrStr: String;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnGitPageValidate index=' + IntToStr(Page.SelectedValueIndex));
if Page.SelectedValueIndex = GitSelectionInstallIndex then
begin
GitUseExisting := False;
GitExecutablePath := '';
GitPath := '';
GitVersion := '{#GitVersion}';
Result := True;
end else if Page.SelectedValueIndex = GitSelectionCustomPathIndex then
begin
GitPath := ChoicePageGetInputText(Page);
GitExecutablePath := GitPath + '\git.exe';
if not FileExists(GitExecutablePath) then
begin
MsgBox('Can not find git.exe in ' + GitPath, mbError, MB_OK);
Result := False;
exit;
end;
if not GetVersionOfGitExe(GitExecutablePath, Version, ErrStr) then
begin
MsgBox('Can not determine version of git.exe.' + #13#10
+ 'Please check that this copy of git works from cmd.exe.', mbError, MB_OK);
Result := False;
exit;
end;
Log('Version of ' + GitExecutablePath + ' is ' + Version);
if not GitVersionSupported(Version) then
begin
MsgBox('Selected git version (' + Version + ') is not supported.', mbError, MB_OK);
Result := False;
exit;
end;
Log('Version of git is supported');
GitUseExisting := True;
GitVersion := Version;
end else begin
GitUseExisting := True;
GitExecutablePath := InstalledGitExecutables[Page.SelectedValueIndex];
GitPath := ExtractFilePath(GitExecutablePath);
GitVersion := InstalledGitVersions[Page.SelectedValueIndex];
Result := True;
end;
end;
procedure GitExecutablePathUpdateAfterInstall();
var
GitInstallPath: String;
begin
GitInstallPath := GetInstallPath('SOFTWARE\GitForWindows', 'InstallPath');
if GitInstallPath = '' then
begin
Log('Failed to find Git install path');
exit;
end;
GitPath := GitInstallPath + '\cmd';
GitExecutablePath := GitPath + '\git.exe';
end;
<event('InitializeWizard')>
procedure CreateGitPage();
begin
GitPage := ChoicePageCreate(
wpLicense,
'Git choice', 'Please choose Git version',
'Available Git versions',
'Enter custom location of git.exe',
True,
@OnGitPagePrepare,
@OnGitSelectionChange,
@OnGitPageValidate);
end;

View file

@ -0,0 +1,117 @@
@echo off
:: This script is called from a shortcut (cmd.exe /k export_fallback.bat), with
:: the working directory set to an ESP-IDF directory.
:: Its purpose is to support using the "IDF Tools Directory" method of
:: installation for ESP-IDF versions older than IDF v4.0.
:: It does the same thing as "export.bat" in IDF v4.0.
set IDF_PATH=%CD%
if not exist "%IDF_PATH%\tools\idf.py" (
echo This script must be invoked from ESP-IDF directory.
goto :end
)
if "%~2"=="" (
echo Usage: idf_cmd_init.bat ^<Python directory^> ^<Git directory^>
echo This script must be invoked from ESP-IDF directory.
goto :end
)
set IDF_PYTHON_DIR=%1
set IDF_GIT_DIR=%2
:: Strip quoutes
set "IDF_PYTHON_DIR=%IDF_PYTHON_DIR:"=%"
set "IDF_GIT_DIR=%IDF_GIT_DIR:"=%"
:: Clear PYTHONPATH as it may contain libraries of other Python versions
if not "%PYTHONPATH%"=="" (
echo Clearing PYTHONPATH, was set to %PYTHONPATH%
set PYTHONPATH=
)
:: Add Python and Git paths to PATH
set "PATH=%IDF_PYTHON_DIR%;%IDF_GIT_DIR%;%PATH%"
echo Using Python in %IDF_PYTHON_DIR%
python.exe --version
echo Using Git in %IDF_GIT_DIR%
git.exe --version
:: Check if this is a recent enough copy of ESP-IDF.
:: If so, use export.bat provided there.
:: Note: no "call", will not return into this batch file.
if exist "%IDF_PATH%\export.bat" %IDF_PATH%\export.bat
echo IDF version does not include export.bat. Using the fallback version.
if exist "%IDF_PATH%\tools\tools.json" (
set "IDF_TOOLS_JSON_PATH=%IDF_PATH%\tools\tools.json"
) else (
echo IDF version does not include tools\tools.json. Using the fallback version.
set "IDF_TOOLS_JSON_PATH=%~dp0%tools_fallback.json"
)
if exist "%IDF_PATH%\tools\idf_tools.py" (
set "IDF_TOOLS_PY_PATH=%IDF_PATH%\tools\idf_tools.py"
) else (
echo IDF version does not include tools\idf_tools.py. Using the fallback version.
set "IDF_TOOLS_PY_PATH=%~dp0%idf_tools_fallback.py"
)
echo.
echo Setting IDF_PATH: %IDF_PATH%
echo.
set "OLD_PATH=%PATH%"
echo Adding ESP-IDF tools to PATH...
:: Export tool paths and environment variables.
:: It is possible to do this without a temporary file (running idf_tools.py from for /r command),
:: but that way it is impossible to get the exit code of idf_tools.py.
set "IDF_TOOLS_EXPORTS_FILE=%TEMP%\idf_export_vars.tmp"
python.exe %IDF_TOOLS_PY_PATH% --tools-json %IDF_TOOLS_JSON_PATH% export --format key-value >"%IDF_TOOLS_EXPORTS_FILE%"
if %errorlevel% neq 0 goto :end
for /f "usebackq tokens=1,2 eol=# delims==" %%a in ("%IDF_TOOLS_EXPORTS_FILE%") do (
call set "%%a=%%b"
)
:: This removes OLD_PATH substring from PATH, leaving only the paths which have been added,
:: and prints semicolon-delimited components of the path on separate lines
call set PATH_ADDITIONS=%%PATH:%OLD_PATH%=%%
if "%PATH_ADDITIONS%"=="" call :print_nothing_added
if not "%PATH_ADDITIONS%"=="" echo %PATH_ADDITIONS:;=&echo. %
echo Checking if Python packages are up to date...
python.exe %IDF_PATH%\tools\check_python_dependencies.py
if %errorlevel% neq 0 goto :end
echo.
echo Done! You can now compile ESP-IDF projects.
echo Go to the project directory and run:
echo.
echo idf.py build
echo.
goto :end
:print_nothing_added
echo No directories added to PATH:
echo.
echo %PATH%
echo.
goto :eof
:end
:: Clean up
if not "%IDF_TOOLS_EXPORTS_FILE%"=="" (
del "%IDF_TOOLS_EXPORTS_FILE%" 1>nul 2>nul
)
set IDF_TOOLS_EXPORTS_FILE=
set IDF_PYTHON_DIR=
set IDF_GIT_DIR=
set IDF_TOOLS_PY_PATH=
set IDF_TOOLS_JSON_PATH=
set OLD_PATH=
set PATH_ADDITIONS=

View file

@ -0,0 +1,142 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Page to select the version of ESP-IDF to download ------------------------------ }
var
IDFDownloadPage: TInputOptionWizardPage;
IDFDownloadAvailableVersions: TArrayOfString;
IDFDownloadPath, IDFDownloadVersion: String;
function GetSuggestedIDFDirectory(): String;
var
BaseName: String;
RepeatIndex: Integer;
begin
{ Start with Desktop\esp-idf name and if it already exists,
keep trying with Desktop\esp-idf-N for N=2 and above. }
BaseName := ExpandConstant('{userdesktop}\esp-idf');
Result := BaseName;
RepeatIndex := 1;
while DirExists(Result) do
begin
RepeatIndex := RepeatIndex + 1;
Result := BaseName + '-' + IntToStr(RepeatIndex);
end;
end;
function GetIDFVersionDescription(Version: String): String;
begin
if WildCardMatch(Version, 'v*-beta*') then
Result := 'beta version'
else if WildCardMatch(Version, 'v*-rc*') then
Result := 'pre-release version'
else if WildCardMatch(Version, 'v*') then
Result := 'release version'
else if WildCardMatch(Version, 'release/v*') then
Result := 'release branch'
else if WildCardMatch(Version, 'master') then
Result := 'development branch'
else
Result := '';
end;
procedure DownloadIDFVersionsList();
var
Url: String;
VersionFile: String;
begin
Url := '{#IDFVersionsURL}';
VersionFile := ExpandConstant('{tmp}\idf_versions.txt');
if idpDownloadFile(Url, VersionFile) then
begin
Log('Downloaded ' + Url + ' to ' + VersionFile);
end else begin
Log('Download of ' + Url + ' failed, using a fallback versions list');
ExtractTemporaryFile('idf_versions.txt');
end;
end;
procedure OnIDFDownloadPagePrepare(Sender: TObject);
var
Page: TInputOptionWizardPage;
VersionFile: String;
i: Integer;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnIDFDownloadPagePrepare');
if Page.CheckListBox.Items.Count > 0 then
exit;
DownloadIDFVersionsList();
VersionFile := ExpandConstant('{tmp}\idf_versions.txt');
if not LoadStringsFromFile(VersionFile, IDFDownloadAvailableVersions) then
begin
Log('Failed to load versions from ' + VersionFile);
exit;
end;
Log('Versions count: ' + IntToStr(GetArrayLength(IDFDownloadAvailableVersions)))
for i := 0 to GetArrayLength(IDFDownloadAvailableVersions) - 1 do
begin
Log('Version ' + IntToStr(i) + ': ' + IDFDownloadAvailableVersions[i]);
Page.Add(IDFDownloadAvailableVersions[i] + ' ('
+ GetIDFVersionDescription(IDFDownloadAvailableVersions[i]) + ')');
end;
Page.SelectedValueIndex := 0;
ChoicePageSetInputText(Page, GetSuggestedIDFDirectory());
end;
procedure OnIDFDownloadSelectionChange(Sender: TObject);
var
Page: TInputOptionWizardPage;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnIDFDownloadSelectionChange index=' + IntToStr(Page.SelectedValueIndex));
end;
function OnIDFDownloadPageValidate(Sender: TWizardPage): Boolean;
var
Page: TInputOptionWizardPage;
IDFPath: String;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnIDFDownloadPageValidate index=' + IntToStr(Page.SelectedValueIndex));
IDFPath := ChoicePageGetInputText(Page);
if DirExists(IDFPath) and not DirIsEmpty(IDFPath) then
begin
MsgBox('Directory already exists and is not empty:' + #13#10 +
IDFPath + #13#10 + 'Please choose a different directory.', mbError, MB_OK);
Result := False;
exit;
end;
IDFDownloadPath := IDFPath;
IDFDownloadVersion := IDFDownloadAvailableVersions[Page.SelectedValueIndex];
Result := True;
end;
<event('ShouldSkipPage')>
function ShouldSkipIDFDownloadPage(PageID: Integer): Boolean;
begin
if (PageID = IDFDownloadPage.ID) and not IDFDownloadRequired() then
Result := True;
end;
<event('InitializeWizard')>
procedure CreateIDFDownloadPage();
begin
IDFDownloadPage := ChoicePageCreate(
IDFPage.ID,
'Download ESP-IDF', 'Please choose ESP-IDF version to download',
'For more information about ESP-IDF versions, see' + #13#10 +
'https://docs.espressif.com/projects/esp-idf/en/latest/versions.html',
'Choose a directory to download ESP-IDF to',
True,
@OnIDFDownloadPagePrepare,
@OnIDFDownloadSelectionChange,
@OnIDFDownloadPageValidate);
end;

View file

@ -0,0 +1,111 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Page to select whether to download ESP-IDF, or use an existing copy ------------------------------ }
var
IDFPage: TInputOptionWizardPage;
IDFSelectionDownloadIndex: Integer;
IDFSelectionCustomPathIndex: Integer;
IDFUseExisting: Boolean;
IDFExistingPath: String;
function IDFDownloadRequired(): Boolean;
begin
Result := not IDFUseExisting;
end;
procedure IDFPageUpdateInput();
var
Enable: Boolean;
begin
if IDFPage.SelectedValueIndex = IDFSelectionCustomPathIndex then
Enable := True;
ChoicePageSetInputEnabled(IDFPage, Enable);
end;
procedure OnIDFPagePrepare(Sender: TObject);
var
Page: TInputOptionWizardPage;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnIDFPagePrepare');
if Page.CheckListBox.Items.Count > 0 then
exit;
IDFSelectionDownloadIndex := Page.Add('Download ESP-IDF')
IDFSelectionCustomPathIndex := Page.Add('Use an existing ESP-IDF directory');
Page.SelectedValueIndex := 0;
IDFPageUpdateInput();
end;
procedure OnIDFSelectionChange(Sender: TObject);
var
Page: TInputOptionWizardPage;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnIDFSelectionChange index=' + IntToStr(Page.SelectedValueIndex));
IDFPageUpdateInput();
end;
function OnIDFPageValidate(Sender: TWizardPage): Boolean;
var
Page: TInputOptionWizardPage;
NotSupportedMsg, IDFPath, IDFPyPath, RequirementsPath: String;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnIDFPageValidate index=' + IntToStr(Page.SelectedValueIndex));
if Page.SelectedValueIndex = IDFSelectionDownloadIndex then
begin
IDFUseExisting := False;
Result := True;
end else begin
IDFUseExisting := True;
Result := False;
NotSupportedMsg := 'The selected version of ESP-IDF is not supported:' + #13#10;
IDFPath := ChoicePageGetInputText(Page);
if not DirExists(IDFPath) then
begin
MsgBox('Directory doesn''t exist: ' + IDFPath + #13#10 +
'Please choose an existing ESP-IDF directory', mbError, MB_OK);
exit;
end;
IDFPyPath := IDFPath + '\tools\idf.py';
if not FileExists(IDFPyPath) then
begin
MsgBox(NotSupportedMsg +
'Can not find idf.py in ' + IDFPath + '\tools', mbError, MB_OK);
exit;
end;
RequirementsPath := IDFPath + '\requirements.txt';
if not FileExists(RequirementsPath) then
begin
MsgBox(NotSupportedMsg +
'Can not find requirements.txt in ' + IDFPath, mbError, MB_OK);
exit;
end;
IDFExistingPath := IDFPath;
Result := True;
end;
end;
<event('InitializeWizard')>
procedure CreateIDFPage();
begin
IDFPage := ChoicePageCreate(
wpLicense,
'Download or use ESP-IDF', 'Please choose ESP-IDF version to download, or use an existing ESP-IDF copy',
'Available ESP-IDF versions',
'Choose existing ESP-IDF directory',
True,
@OnIDFPagePrepare,
@OnIDFSelectionChange,
@OnIDFPageValidate);
end;

View file

@ -0,0 +1,255 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Downloading ESP-IDF ------------------------------ }
var
IDFZIPFileVersion, IDFZIPFileName: String;
function GetIDFPath(Unused: String): String;
begin
if IDFUseExisting then
Result := IDFExistingPath
else
Result := IDFDownloadPath;
end;
function GetIDFZIPFileVersion(Version: String): String;
var
ReleaseVerPart: String;
i: Integer;
Found: Boolean;
begin
if WildCardMatch(Version, 'v*') or WildCardMatch(Version, 'v*-rc*') then
Result := Version
else if Version = 'master' then
Result := ''
else if WildCardMatch(Version, 'release/v*') then
begin
ReleaseVerPart := Version;
Log('ReleaseVerPart=' + ReleaseVerPart)
Delete(ReleaseVerPart, 1, Length('release/'));
Log('ReleaseVerPart=' + ReleaseVerPart)
Found := False;
for i := 0 to GetArrayLength(IDFDownloadAvailableVersions) - 1 do
begin
if Pos(ReleaseVerPart, IDFDownloadAvailableVersions[i]) = 1 then
begin
Result := IDFDownloadAvailableVersions[i];
Found := True;
break;
end;
end;
if not Found then
Result := '';
end;
Log('GetIDFZIPFileVersion(' + Version + ')=' + Result);
end;
procedure IDFAddDownload();
var
Url, MirrorUrl: String;
begin
IDFZIPFileVersion := GetIDFZIPFileVersion(IDFDownloadVersion);
if IDFZIPFileVersion <> '' then
begin
Url := 'https://github.com/espressif/esp-idf/releases/download/' + IDFZIPFileVersion + '/esp-idf-' + IDFZIPFileVersion + '.zip';
MirrorUrl := 'https://dl.espressif.com/dl/esp-idf/releases/esp-idf-' + IDFZIPFileVersion + '.zip';
IDFZIPFileName := ExpandConstant('{app}\releases\esp-idf-' + IDFZIPFileVersion + '.zip')
if not FileExists(IDFZIPFileName) then
begin
ForceDirectories(ExpandConstant('{app}\releases'))
Log('Adding download: ' + Url + ', mirror: ' + MirrorUrl + ', destination: ' + IDFZIPFileName);
idpAddFile(Url, IDFZIPFileName);
idpAddMirror(Url, MirrorUrl);
end else begin
Log(IDFZIPFileName + ' already exists')
end;
end;
end;
procedure RemoveAlternatesFile(Path: String);
begin
Log('Removing ' + Path);
DeleteFile(Path);
end;
{
Replacement of the '--dissociate' flag of 'git clone', to support older versions of Git.
'--reference' is supported for submodules since git 2.12, but '--dissociate' only from 2.18.
}
procedure GitRepoDissociate(Path: String);
var
CmdLine: String;
begin
CmdLine := GitExecutablePath + ' -C ' + Path + ' repack -d -a'
DoCmdlineInstall('Finishing ESP-IDF installation', 'Re-packing the repository', CmdLine);
CmdLine := GitExecutablePath + ' -C ' + Path + ' submodule foreach git repack -d -a'
DoCmdlineInstall('Finishing ESP-IDF installation', 'Re-packing the submodules', CmdLine);
FindFileRecusive(Path + '\.git', 'alternates', @RemoveAlternatesFile);
end;
{ Run git reset --hard in the repo and in the submodules, to fix the newlines. }
procedure GitRepoFixNewlines(Path: String);
var
CmdLine: String;
begin
CmdLine := GitExecutablePath + ' -C ' + Path + ' reset --hard';
Log('Resetting the repository: ' + CmdLine);
DoCmdlineInstall('Finishing ESP-IDF installation', 'Updating newlines', CmdLine);
Log('Resetting the submodules: ' + CmdLine);
CmdLine := GitExecutablePath + ' -C ' + Path + ' submodule foreach git reset --hard';
DoCmdlineInstall('Finishing ESP-IDF installation', 'Updating newlines in submodules', CmdLine);
end;
{
There are 3 possible ways how an ESP-IDF copy can be obtained:
- Download the .zip archive with submodules included, extract to destination directory,
then do 'git reset --hard' and 'git submodule foreach git reset --hard' to correct for
possibly different newlines. This is done for release versions.
- Do a git clone of the Github repository into the destination directory.
This is done for the master branch.
- Download the .zip archive of a "close enough" release version, extract into a temporary
directory. Then do a git clone of the Github repository, using the temporary directory
as a '--reference'. This is done for other versions (such as release branches).
}
procedure IDFDownload();
var
CmdLine: String;
IDFTempPath: String;
IDFPath: String;
NeedToClone: Boolean;
Res: Boolean;
begin
IDFPath := IDFDownloadPath;
{ If there is a release archive to download, IDFZIPFileName and IDFZIPFileVersion will be set.
See GetIDFZIPFileVersion function.
}
if IDFZIPFileName <> '' then
begin
if IDFZIPFileVersion <> IDFDownloadVersion then
begin
{ The version of .zip file downloaded is not the same as the version the user has requested.
Will use 'git clone --reference' to obtain the correct version, using the contents
of the .zip file as reference.
}
NeedToClone := True;
end;
ExtractTemporaryFile('7za.exe')
CmdLine := ExpandConstant('{tmp}\7za.exe x -o' + ExpandConstant('{tmp}') + ' -r -aoa ' + IDFZIPFileName);
IDFTempPath := ExpandConstant('{tmp}\esp-idf-') + IDFZIPFileVersion;
Log('Extracting ESP-IDF reference repository: ' + CmdLine);
Log('Reference repository path: ' + IDFTempPath);
DoCmdlineInstall('Extracting ESP-IDF', 'Setting up reference repository', CmdLine);
end else begin
{ IDFZIPFileName is not set, meaning that we will rely on 'git clone'. }
NeedToClone := True;
Log('Not .zip release archive. Will do full clone.');
end;
if NeedToClone then
begin
CmdLine := GitExecutablePath + ' clone --recursive --progress -b ' + IDFDownloadVersion;
if IDFTempPath <> '' then
CmdLine := CmdLine + ' --reference ' + IDFTempPath;
CmdLine := CmdLine + ' https://github.com/espressif/esp-idf.git ' + IDFPath;
Log('Cloning IDF: ' + CmdLine);
DoCmdlineInstall('Downloading ESP-IDF', 'Using git to clone ESP-IDF repository', CmdLine);
if IDFTempPath <> '' then
GitRepoDissociate(IDFPath);
end else begin
Log('Moving ' + IDFTempPath + ' to ' + IDFPath);
if DirExists(IDFPath) then
begin
if not DirIsEmpty(IDFPath) then
begin
MsgBox('Destination directory exists and is not empty: ' + IDFPath, mbError, MB_OK);
RaiseException('Failed to copy ESP-IDF')
end;
Res := RemoveDir(IDFPath);
if not Res then
begin
MsgBox('Failed to remove destination directory: ' + IDFPath, mbError, MB_OK);
RaiseException('Failed to copy ESP-IDF')
end;
end;
Res := RenameFile(IDFTempPath, IDFPath);
if not Res then
begin
MsgBox('Failed to copy ESP-IDF to the destination directory: ' + IDFPath, mbError, MB_OK);
RaiseException('Failed to copy ESP-IDF');
end;
GitRepoFixNewlines(IDFPath);
end;
end;
{ ------------------------------ IDF Tools setup, Python environment setup ------------------------------ }
procedure IDFToolsSetup();
var
CmdLine: String;
IDFPath: String;
IDFToolsPyPath: String;
IDFToolsPyCmd: String;
begin
IDFPath := GetIDFPath('');
IDFToolsPyPath := IDFPath + '\tools\idf_tools.py';
if FileExists(IDFToolsPyPath) then
begin
Log('idf_tools.py exists in IDF directory');
IDFToolsPyCmd := PythonExecutablePath + ' ' + IDFToolsPyPath;
end else begin
Log('idf_tools.py does not exist in IDF directory, using a fallback version');
IDFToolsPyCmd := ExpandConstant(PythonExecutablePath
+ ' {app}\idf_tools_fallback.py'
+ ' --idf-path ' + IDFPath
+ ' --tools {app}\tools_fallback.json');
end;
Log('idf_tools.py command: ' + IDFToolsPyCmd);
CmdLine := IDFToolsPyCmd + ' install';
Log('Installing tools:' + CmdLine);
DoCmdlineInstall('Installing ESP-IDF tools', '', CmdLine);
CmdLine := IDFToolsPyCmd + ' install-python-env';
Log('Installing Python environment:' + CmdLine);
DoCmdlineInstall('Installing Python environment', '', CmdLine);
end;
{ ------------------------------ Start menu shortcut ------------------------------ }
procedure CreateIDFCommandPromptShortcut();
var
Destination: String;
Description: String;
Command: String;
begin
ForceDirectories(ExpandConstant('{group}'));
Destination := ExpandConstant('{group}\{#IDFCmdExeShortcutFile}');
Description := '{#IDFCmdExeShortcutDescription}';
Command := ExpandConstant('/k {app}\idf_cmd_init.bat "') + PythonPath + '" "' + GitPath + '"';
Log('CreateShellLink Destination=' + Destination + ' Description=' + Description + ' Command=' + Command)
try
CreateShellLink(
Destination,
Description,
'cmd.exe',
Command,
GetIDFPath(''),
'', 0, SW_SHOWNORMAL);
except
MsgBox('Failed to create the Start menu shortcut: ' + Destination, mbError, MB_OK);
RaiseException('Failed to create the shortcut');
end;
end;

View file

@ -1,242 +1,95 @@
; Copyright 2019 Espressif Systems (Shanghai) PTE LTD
; SPDX-License-Identifier: Apache-2.0
#pragma include __INCLUDE__ + ";" + ReadReg(HKLM, "Software\Mitrich Software\Inno Download Plugin", "InstallDir")
#include <idp.iss>
[Setup]
AppName=ESP-IDF Tools
AppVersion=1.2
OutputBaseFilename=esp-idf-tools-setup-unsigned
#define MyAppName "ESP-IDF Tools"
#define MyAppVersion "2.0"
#define MyAppPublisher "Espressif Systems (Shanghai) Co. Ltd."
#define MyAppURL "https://github.com/espressif/esp-idf"
DefaultDirName={pf}\Espressif\ESP-IDF Tools
DefaultGroupName=ESP-IDF Tools
Compression=lzma2
#define PythonVersion "3.7"
#define PythonInstallerName "python-3.7.3-amd64.exe"
#define PythonInstallerDownloadURL "https://www.python.org/ftp/python/3.7.3/python-3.7.3-amd64.exe"
#define GitVersion "2.21.0"
#define GitInstallerName "Git-2.21.0-64-bit.exe"
#define GitInstallerDownloadURL "https://github.com/git-for-windows/git/releases/download/v2.21.0.windows.1/Git-2.21.0-64-bit.exe"
#define IDFVersionsURL "https://dl.espressif.com/dl/esp-idf/idf_versions.txt"
#define IDFCmdExeShortcutDescription "Open ESP-IDF Command Prompt (cmd.exe)"
#define IDFCmdExeShortcutFile "ESP-IDF Command Prompt (cmd.exe).lnk"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{9E068D99-5C4B-4E5F-96A3-B17CF291E6BD}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={%USERPROFILE}\.espressif
DirExistsWarning=no
DefaultGroupName=ESP-IDF
DisableProgramGroupPage=yes
OutputBaseFilename=esp-idf-tools-setup-unsigned
Compression=lzma
SolidCompression=yes
ChangesEnvironment=yes
LicenseFile=license.txt
; Note: the rest of the installer setup is written to work cleanly on win32 also, *however*
; Ninja doesn't ship a 32-bit binary so there's no way yet to install on win32 :(
; See https://github.com/ninja-build/ninja/issues/1339
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
LicenseFile=license.txt
PrivilegesRequired=lowest
SetupLogging=yes
ChangesEnvironment=yes
WizardStyle=modern
[Types]
Name: "full"; Description: "Default installation"
Name: "custom"; Description: "Custom installation"; Flags: iscustom
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Components]
Name: xtensa_esp32; Description: ESP32 Xtensa GCC Cross-Toolchain; Types: full custom;
Name: mconf_idf; Description: ESP-IDF console menuconfig tool; Types: full custom;
Name: openocd_esp32; Description: openocd debug interface for ESP32; Types: full custom;
Name: esp32ulp_elf_binutils; Description: ULP binutils toolchain for ESP32; Types: full custom;
Name: ninja; Description: Install Ninja build v1.8.2; Types: full custom
[Tasks]
; Should installer prepend to Path (does this by default)
Name: addpath; Description: "Add tools to Path"; GroupDescription: "Add to Path:";
Name: addpath\allusers; Description: "For all users"; GroupDescription: "Add to Path:"; Flags: exclusive
Name: addpath\user; Description: "For the current user only"; GroupDescription: "Add to Path:"; Flags: exclusive unchecked
; External installation tasks
;
; Note: The Check conditions here auto-select 32-bit or 64-bit installers, as needed
; The tasks won't appear if CMake/Python27 already appear to be installed on this system
Name: cmake32; Description: Download and Run CMake 3.11.1 Installer; GroupDescription: "Other Required Tools:"; Check: not IsWin64 and not CMakeInstalled
Name: cmake64; Description: Download and Run CMake 3.11.1 Installer; GroupDescription: "Other Required Tools:"; Check: IsWin64 and not CMakeInstalled
Name: python32; Description: Download and Run Python 2.7.14 Installer and install Python dependencies; GroupDescription: "Other Required Tools:"; Check: not IsWin64 and not Python27Installed
Name: python64; Description: Download and Run Python 2.7.14 Installer and install Python dependencies; GroupDescription: "Other Required Tools:"; Check: IsWin64 and not Python27Installed
Name: python_requirements; Description: Install any missing Python dependencies; GroupDescription: "Other Required Tools:"; Check: Python27Installed
[Dirs]
Name: "{app}\dist"
[Files]
Components: xtensa_esp32; Source: "input\xtensa-esp32-elf\*"; DestDir: "{app}\tools\"; Flags: recursesubdirs;
Components: mconf_idf; Source: "input\mconf-v4.6.0.0-idf-20180525-win32\*"; DestDir: "{app}\mconf-idf\";
Components: esp32ulp_elf_binutils; Source: "input\esp32ulp-elf-binutils\*"; DestDir: "{app}\tools\"; Flags: recursesubdirs;
; Excludes for openocd are because some config files contain Cyrillic characters and inno can't encode them
Components: openocd_esp32; Source: "input\openocd-esp32\*"; DestDir: "{app}\tools\"; Flags: recursesubdirs; Excludes: "target\1986*.cfg,target\*1879*.cfg"
Components: ninja; Source: "input\ninja.exe"; DestDir: "{app}\tools\bin\";
Tasks: python32 python64 python_requirements; Source: "..\..\..\requirements.txt"; DestDir: "{tmp}"; Flags: deleteafterinstall;
Source: "cmdlinerunner\build\cmdlinerunner.dll"; Flags: dontcopy
Source: "unzip\7za.exe"; Flags: dontcopy
Source: "idf_versions.txt"; Flags: dontcopy
Source: "..\..\idf_tools.py"; DestDir: "{app}"; DestName: "idf_tools_fallback.py"
; Note: this tools.json matches the requirements of IDF v3.x versions.
Source: "tools_fallback.json"; DestDir: "{app}"; DestName: "tools_fallback.json"
Source: "idf_cmd_init.bat"; DestDir: "{app}"
Source: "dist\*"; DestDir: "{app}\dist"
[UninstallDelete]
Type: filesandordirs; Name: "{app}\dist"
Type: filesandordirs; Name: "{app}\releases"
Type: filesandordirs; Name: "{app}\tools"
Type: filesandordirs; Name: "{app}\python_env"
[Run]
Tasks: cmake32 cmake64; Filename: "msiexec.exe"; Parameters: "/i ""{tmp}\cmake.msi"" /qb! {code:GetCMakeInstallerArgs}"; StatusMsg: Running CMake installer...;
Tasks: python32 python64; Filename: "msiexec.exe"; Parameters: "/i ""{tmp}\python.msi"" /qb! {code:GetPythonInstallerArgs} REBOOT=Supress"; StatusMsg: Running Python installer...;
Tasks: python32 python64; Filename: "C:\Python27\Scripts\pip.exe"; Parameters: "install -r ""{tmp}\requirements.txt"""; StatusMsg: Installing Python modules...;
Tasks: python_requirements; Filename: "{code:Python27InstallPathInclude}\Scripts\pip.exe"; Parameters: "install -r ""{tmp}\requirements.txt"""; StatusMsg: Installing Python modules...;
Filename: "{app}\dist\{#PythonInstallerName}"; Parameters: "/passive PrependPath=1 InstallLauncherAllUsers=0 Include_dev=0 Include_tcltk=0 Include_launcher=0 Include_test=0 Include_doc=0"; Description: "Installing Python"; Check: PythonInstallRequired
Filename: "{app}\dist\{#GitInstallerName}"; Parameters: "/silent /tasks="""" /norestart"; Description: "Installing Git"; Check: GitInstallRequired
Filename: "{group}\{#IDFCmdExeShortcutFile}"; Flags: postinstall shellexec; Description: "Run ESP-IDF Command Prompt (cmd.exe)"; Check: InstallationSuccessful
[Registry]
; Prepend various entries to Path in the registry. Can either be HKLM (all users) or HKCU (single user only)
; "tools" bin dir (ninja, xtensa & ULP toolchains, openocd all in this dir)
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "Path"; ValueData: "{app}\tools\bin;{olddata}"; Check: not IsInPath('{app}'); \
Components: xtensa_esp32 esp32ulp_elf_binutils openocd_esp32 ninja; Tasks: addpath\allusers
Root: HKCU; Subkey: "Environment"; \
ValueType: expandsz; ValueName: "Path"; ValueData: "{app}\tools\bin;{olddata}"; Check: not IsInPath('{app}'); \
Components: xtensa_esp32 esp32ulp_elf_binutils openocd_esp32 ninja; Tasks: addpath\user
; mconf-idf path
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "Path"; ValueData: "{app}\mconf-idf;{olddata}"; Check: not IsInPath('{app}\mconf-idf'); \
Components: mconf_idf; Tasks: addpath\allusers
Root: HKCU; Subkey: "Environment"; \
ValueType: expandsz; ValueName: "Path"; ValueData: "{app}\mconf-idf;{olddata}"; Check: not IsInPath('{app}\mconf-idf'); \
Components: mconf_idf; Tasks: addpath\user
; set OPENOCD_SCRIPTS environment variable
[Registry]
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType:string; ValueName: "OPENOCD_SCRIPTS"; \
ValueData: "{app}\tools\share\openocd\scripts"; Flags: preservestringtype createvalueifdoesntexist; \
Components: openocd_esp32; Tasks: addpath\allusers
Root: HKCU; Subkey: "Environment"; ValueType:string; ValueName: "OPENOCD_SCRIPTS"; \
ValueData: "{app}\tools\share\openocd\scripts"; Flags: preservestringtype createvalueifdoesntexist; \
Components: openocd_esp32; Tasks: addpath\user
Root: HKCU; Subkey: "Environment"; ValueType: string; ValueName: "IDF_TOOLS_PATH"; \
ValueData: "{app}"; Flags: preservestringtype createvalueifdoesntexist;
[Code]
procedure InitializeWizard;
begin
idpDownloadAfter(wpReady);
end;
procedure CurPageChanged(CurPageID: Integer);
begin
{ When the Ready page is being displayed, initialise downloads based on which Tasks are selected }
if CurPageID=wpReady then
begin
if IsTaskSelected('python32') then
begin
idpAddFile('https://www.python.org/ftp/python/2.7.14/python-2.7.14.msi', ExpandConstant('{tmp}\python.msi'));
end;
if IsTaskSelected('python64') then
begin
idpAddFile('https://www.python.org/ftp/python/2.7.14/python-2.7.14.amd64.msi', ExpandConstant('{tmp}\python.msi'));
end;
if IsTaskSelected('cmake32') then
begin
idpAddFile('https://cmake.org/files/v3.11/cmake-3.11.1-win32-x86.msi', ExpandConstant('{tmp}\cmake.msi'));
end;
if IsTaskSelected('cmake64') then
begin
idpAddFile('https://cmake.org/files/v3.11/cmake-3.11.1-win64-x64.msi', ExpandConstant('{tmp}\cmake.msi'));
end;
end;
end;
{ Utility to search in HKLM for an installation path. Looks in both 64-bit & 32-bit registry. }
function GetInstallPath(key, valuename : String) : Variant;
var
value : string;
begin
Result := Null;
if RegQueryStringValue(HKEY_LOCAL_MACHINE, key, valuename, value) then
begin
Result := value;
end
else
begin
{ This is 32-bit setup running on 64-bit Windows, but ESP-IDF can use 64-bit tools also }
if IsWin64 and RegQueryStringValue(HKLM64, key, valuename, value) then
begin
Result := value;
end;
end;
end;
{ Return the path of the CMake install, if there is one }
function CMakeInstallPath() : Variant;
begin
Result := GetInstallPath('SOFTWARE\Kitware\CMake', 'InstallDir');
end;
{ Return 'True' if CMake is installed }
function CMakeInstalled() : Boolean;
begin
Result := not VarIsNull(CMakeInstallPath());
end;
{ Return the path where Python 2.7 is installed, if there is one }
function Python27InstallPath() : Variant;
begin
Result := GetInstallPath('SOFTWARE\Python\PythonCore\2.7\InstallPath', '');
end;
{ Return the path where Python 2.7 is installed, suitable for including in code: tag }
function Python27InstallPathInclude(Ignored : String) : String;
begin
Result := Python27InstallPath();
end;
{ Return True if Python 2.7 is installed }
function Python27Installed() : Boolean;
begin
Result := not VarIsNull(Python27InstallPath());
end;
{ Return arguments to pass to CMake installer, ie should it add CMake to the Path }
function GetCMakeInstallerArgs(Param : String) : String;
begin
if IsTaskSelected('addpath\allusers') then
begin
Result := 'ADD_CMAKE_TO_PATH=System';
end
else if IsTaskSelected('addpath\user') then
begin
Result := 'ADD_CMAKE_TO_PATH=User';
end
else begin
Result := 'ADD_CMAKE_TO_PATH=None';
end;
end;
{ Return arguments to pass to the Python installer,
ie should it install for all users and should it prepend to the Path }
function GetPythonInstallerArgs(Param : String) : String;
begin
{ Note: The Python 2.7 installer appears to always add PATH to
system environment variables, regardless of ALLUSERS setting.
This appears to be fixed in the Python 3.x installers (which use WiX) }
if IsTaskSelected('addpath') then
begin
Result := 'ADDLOCAL=ALL ';
end
else begin
Result := ''
end;
if IsTaskSelected('addpath\allusers') then
begin
Result := Result + 'ALLUSERS=1';
end
else begin
Result := Result + 'ALLUSERS=';
end;
end;
{ Return True if the param is already set in the Path
(user or system, depending on which Task is chosen)
Adapted from https://stackoverflow.com/a/3431379
}
function IsInPath(Param: string): boolean;
var
OrigPath: string;
RootKey : Integer;
SubKey : String;
begin
if IsTaskSelected('addpath\allusers') then
begin
RootKey := HKEY_LOCAL_MACHINE;
SubKey := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
end
else begin
RootKey := HKEY_CURRENT_USER;
SubKey := 'Environment';
end;
if not RegQueryStringValue(RootKey, SubKey, 'Path', OrigPath)
then begin
Result := False;
end
else begin
{ look for the path with leading and trailing semicolon }
Result := Pos(';' + Param + ';', ';' + OrigPath + ';') > 0;
end;
end;
#include "utils.iss.inc"
#include "choice_page.iss.inc"
#include "cmdline_page.iss.inc"
#include "idf_page.iss.inc"
#include "git_page.iss.inc"
#include "python_page.iss.inc"
#include "idf_download_page.iss.inc"
#include "idf_setup.iss.inc"
#include "summary.iss.inc"
#include "main.iss.inc"

View file

@ -0,0 +1,121 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Custom steps before the main installation flow ------------------------------ }
var
SetupAborted: Boolean;
function InstallationSuccessful(): Boolean;
begin
Result := not SetupAborted;
end;
<event('InitializeWizard')>
procedure InitializeDownloader();
begin
idpDownloadAfter(wpReady);
end;
<event('NextButtonClick')>
function PreInstallSteps(CurPageID: Integer): Boolean;
var
DestPath: String;
begin
Result := True;
if CurPageID <> wpReady then
exit;
ForceDirectories(ExpandConstant('{app}\dist'));
if not PythonUseExisting then
begin
DestPath := ExpandConstant('{app}\dist\{#PythonInstallerName}');
if FileExists(DestPath) then
begin
Log('Python installer already downloaded: ' + DestPath);
end else begin
idpAddFile('{#PythonInstallerDownloadURL}', DestPath);
end;
end;
if not GitUseExisting then
begin
DestPath := ExpandConstant('{app}\dist\{#GitInstallerName}');
if FileExists(DestPath) then
begin
Log('Git installer already downloaded: ' + DestPath);
end else begin
idpAddFile('{#GitInstallerDownloadURL}', DestPath);
end;
end;
if not IDFUseExisting then
begin
IDFAddDownload();
end;
end;
{ ------------------------------ Custom steps after the main installation flow ------------------------------ }
procedure AddPythonGitToPath();
var
EnvPath: String;
PythonLibPath: String;
begin
EnvPath := GetEnv('PATH');
if not PythonUseExisting then
PythonExecutablePathUpdateAfterInstall();
if not GitUseExisting then
GitExecutablePathUpdateAfterInstall();
EnvPath := PythonPath + ';' + GitPath + ';' + EnvPath;
Log('Setting PATH for this process: ' + EnvPath);
SetEnvironmentVariable('PATH', EnvPath);
{ Log and clear PYTHONPATH variable, as it might point to libraries of another Python version}
PythonLibPath := GetEnv('PYTHONPATH')
Log('PYTHONPATH=' + PythonLibPath)
SetEnvironmentVariable('PYTHONPATH', '')
end;
<event('CurStepChanged')>
procedure PostInstallSteps(CurStep: TSetupStep);
var
Err: Integer;
begin
if CurStep <> ssPostInstall then
exit;
try
AddPythonGitToPath();
if not IDFUseExisting then
IDFDownload();
IDFToolsSetup();
CreateIDFCommandPromptShortcut();
except
SetupAborted := True;
if MsgBox('Installation log has been created, it may contain more information about the problem.' + #13#10
+ 'Display the installation log now?', mbConfirmation, MB_YESNO or MB_DEFBUTTON1) = IDYES then
begin
ShellExec('', 'notepad.exe', ExpandConstant('{log}'), ExpandConstant('{tmp}'), SW_SHOW, ewNoWait, Err);
end;
Abort();
end;
end;
<event('ShouldSkipPage')>
function SkipFinishedPage(PageID: Integer): Boolean;
begin
Result := False;
if PageID = wpFinished then
begin
Result := SetupAborted;
end;
end;

View file

@ -0,0 +1,113 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Find installed Python interpreters in Windows Registry (see PEP 514) ------------------------------ }
var
InstalledPythonVersions: TStringList;
InstalledPythonDisplayNames: TStringList;
InstalledPythonExecutables: TStringList;
procedure PythonVersionAdd(Version, DisplayName, Executable: String);
begin
Log('Adding Python version=' + Version + ' name='+DisplayName+' executable='+Executable);
InstalledPythonVersions.Append(Version);
InstalledPythonDisplayNames.Append(DisplayName);
InstalledPythonExecutables.Append(Executable);
end;
function GetPythonVersionInfoFromKey(RootKey: Integer; SubKeyName, CompanyName, TagName: String;
var Version: String;
var DisplayName: String;
var ExecutablePath: String): Boolean;
var
TagKey, InstallPathKey, DefaultPath: String;
begin
TagKey := SubKeyName + '\' + CompanyName + '\' + TagName;
InstallPathKey := TagKey + '\InstallPath';
if not RegQueryStringValue(RootKey, InstallPathKey, '', DefaultPath) then
begin
Log('No (Default) key, skipping');
Result := False;
exit;
end;
if not RegQueryStringValue(RootKey, InstallPathKey, 'ExecutablePath', ExecutablePath) then
begin
Log('No ExecutablePath, using the default');
ExecutablePath := DefaultPath + '\python.exe';
end;
if not RegQueryStringValue(RootKey, TagKey, 'SysVersion', Version) then
begin
if CompanyName = 'PythonCore' then
begin
Version := TagName;
Delete(Version, 4, Length(Version));
end else begin
Log('Can not determine SysVersion');
Result := False;
exit;
end;
end;
if not RegQueryStringValue(RootKey, TagKey, 'DisplayName', DisplayName) then
begin
DisplayName := 'Python ' + Version;
end;
Result := True;
end;
procedure FindPythonVersionsFromKey(RootKey: Integer; SubKeyName: String);
var
CompanyNames: TArrayOfString;
CompanyName, CompanySubKey, TagName, TagSubKey: String;
ExecutablePath, DisplayName, Version: String;
TagNames: TArrayOfString;
CompanyId, TagId: Integer;
begin
if not RegGetSubkeyNames(RootKey, SubKeyName, CompanyNames) then
begin
Log('Nothing found in ' + IntToStr(RootKey) + '\' + SubKeyName);
Exit;
end;
for CompanyId := 0 to GetArrayLength(CompanyNames) - 1 do
begin
CompanyName := CompanyNames[CompanyId];
if CompanyName = 'PyLauncher' then
continue;
CompanySubKey := SubKeyName + '\' + CompanyName;
Log('In ' + IntToStr(RootKey) + '\' + CompanySubKey);
if not RegGetSubkeyNames(RootKey, CompanySubKey, TagNames) then
continue;
for TagId := 0 to GetArrayLength(TagNames) - 1 do
begin
TagName := TagNames[TagId];
TagSubKey := CompanySubKey + '\' + TagName;
Log('In ' + IntToStr(RootKey) + '\' + TagSubKey);
if not GetPythonVersionInfoFromKey(RootKey, SubKeyName, CompanyName, TagName, Version, DisplayName, ExecutablePath) then
continue;
PythonVersionAdd(Version, DisplayName, ExecutablePath);
end;
end;
end;
procedure FindInstalledPythonVersions();
begin
InstalledPythonVersions := TStringList.Create();
InstalledPythonDisplayNames := TStringList.Create();
InstalledPythonExecutables := TStringList.Create();
FindPythonVersionsFromKey(HKEY_CURRENT_USER, 'Software\Python');
FindPythonVersionsFromKey(HKEY_LOCAL_MACHINE, 'Software\Python');
FindPythonVersionsFromKey(HKEY_LOCAL_MACHINE, 'Software\Wow6432Node\Python');
end;

View file

@ -0,0 +1,149 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Page to select Python interpreter ------------------------------ }
#include "python_find_installed.iss.inc"
var
PythonPage: TInputOptionWizardPage;
PythonVersion, PythonPath, PythonExecutablePath: String;
PythonUseExisting: Boolean;
function GetPythonPath(Unused: String): String;
begin
Result := PythonPath;
end;
function PythonInstallRequired(): Boolean;
begin
Result := not PythonUseExisting;
end;
function PythonVersionSupported(Version: String): Boolean;
var
Major, Minor: Integer;
begin
Result := False;
if not VersionExtractMajorMinor(Version, Major, Minor) then
begin
Log('PythonVersionSupported: Could not parse version=' + Version);
exit;
end;
if (Major = 2) and (Minor = 7) then Result := True;
if (Major = 3) and (Minor >= 5) then Result := True;
end;
procedure OnPythonPagePrepare(Sender: TObject);
var
Page: TInputOptionWizardPage;
FullName: String;
i, Index, FirstEnabledIndex: Integer;
OfferToInstall: Boolean;
VersionToInstall: String;
VersionSupported: Boolean;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnPythonPagePrepare');
if Page.CheckListBox.Items.Count > 0 then
exit;
FindInstalledPythonVersions();
VersionToInstall := '{#PythonVersion}';
OfferToInstall := True;
FirstEnabledIndex := -1;
for i := 0 to InstalledPythonVersions.Count - 1 do
begin
VersionSupported := PythonVersionSupported(InstalledPythonVersions[i]);
FullName := InstalledPythonDisplayNames.Strings[i];
if not VersionSupported then
begin
FullName := FullName + ' (unsupported)';
end;
FullName := FullName + #13#10 + InstalledPythonExecutables.Strings[i];
Index := Page.Add(FullName);
if not VersionSupported then
begin
Page.CheckListBox.ItemEnabled[Index] := False;
end else begin
if FirstEnabledIndex < 0 then FirstEnabledIndex := Index;
end;
if InstalledPythonVersions[i] = VersionToInstall then
begin
OfferToInstall := False;
end;
end;
if OfferToInstall then
begin
Index := Page.Add('Install Python ' + VersionToInstall);
if FirstEnabledIndex < 0 then FirstEnabledIndex := Index;
end;
Page.SelectedValueIndex := FirstEnabledIndex;
end;
procedure OnPythonSelectionChange(Sender: TObject);
var
Page: TInputOptionWizardPage;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnPythonSelectionChange index=' + IntToStr(Page.SelectedValueIndex));
end;
function OnPythonPageValidate(Sender: TWizardPage): Boolean;
var
Page: TInputOptionWizardPage;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnPythonPageValidate index=' + IntToStr(Page.SelectedValueIndex));
if Page.SelectedValueIndex < InstalledPythonExecutables.Count then
begin
PythonUseExisting := True;
PythonExecutablePath := InstalledPythonExecutables[Page.SelectedValueIndex];
PythonPath := ExtractFilePath(PythonExecutablePath);
PythonVersion := InstalledPythonVersions[Page.SelectedValueIndex];
end else begin
PythonUseExisting := False;
PythonExecutablePath := '';
PythonPath := '';
PythonVersion := '{#PythonVersion}';
end;
Log('OnPythonPageValidate: PythonPath='+PythonPath+' PythonExecutablePath='+PythonExecutablePath);
Result := True;
end;
procedure PythonExecutablePathUpdateAfterInstall();
var
Version, DisplayName, ExecutablePath: String;
begin
if not GetPythonVersionInfoFromKey(
HKEY_CURRENT_USER, 'Software\Python', 'PythonCore', '{#PythonVersion}',
Version, DisplayName, ExecutablePath) then
begin
Log('Failed to find ExecutablePath for the installed copy of Python');
exit;
end;
Log('Found ExecutablePath for ' + DisplayName + ': ' + ExecutablePath);
PythonExecutablePath := ExecutablePath;
PythonPath := ExtractFilePath(PythonExecutablePath);
Log('PythonExecutablePathUpdateAfterInstall: PythonPath='+PythonPath+' PythonExecutablePath='+PythonExecutablePath);
end;
<event('InitializeWizard')>
procedure CreatePythonPage();
begin
PythonPage := ChoicePageCreate(
wpLicense,
'Python choice', 'Please choose Python version',
'Available Python versions',
'',
False,
@OnPythonPagePrepare,
@OnPythonSelectionChange,
@OnPythonPageValidate);
end;

View file

@ -0,0 +1,40 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Installation summary page ------------------------------ }
function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo,
MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
begin
Result := ''
if PythonUseExisting then
begin
Result := Result + 'Using Python ' + PythonVersion + ':' + NewLine
+ Space + PythonExecutablePath + NewLine + NewLine;
end else begin
Result := Result + 'Will download and install Python ' + PythonVersion + NewLine + NewLine;
end;
if GitUseExisting then
begin
Result := Result + 'Using Git ' + GitVersion + ':' + NewLine
+ Space + GitExecutablePath + NewLine + NewLine;
end else begin
Result := Result + 'Will download and install Git for Windows ' + GitVersion + NewLine + NewLine;
end;
if IDFUseExisting then
begin
Result := Result + 'Using existing ESP-IDF copy: ' + NewLine
+ Space + IDFExistingPath + NewLine + NewLine;
end else begin
Result := Result + 'Will download ESP-IDF ' + IDFDownloadVersion + ' into:' + NewLine
+ Space + IDFDownloadPath + NewLine + NewLine;
end;
Result := Result + 'IDF tools directory (IDF_TOOLS_PATH):' + NewLine +
Space + ExpandConstant('{app}') + NewLine + NewLine;
Log('Summary message: ' + NewLine + Result);
end;

View file

@ -0,0 +1,390 @@
{
"tools": [
{
"description": "Toolchain for Xtensa (ESP32) based on GCC",
"export_paths": [
[
"xtensa-esp32-elf",
"bin"
]
],
"export_vars": {},
"info_url": "https://github.com/espressif/crosstool-NG",
"install": "always",
"license": "GPL-3.0-with-GCC-exception",
"name": "xtensa-esp32-elf",
"version_cmd": [
"xtensa-esp32-elf-gcc",
"--version"
],
"version_regex": "\\(crosstool-NG\\s+(?:crosstool-ng-)?([0-9a-z\\.\\-]+)\\)\\s*([0-9\\.]+)",
"version_regex_replace": "\\1-\\2",
"versions": [
{
"name": "1.22.0-80-g6c4433a5-5.2.0",
"status": "recommended",
"win32": {
"sha256": "f217fccbeaaa8c92db239036e0d6202458de4488b954a3a38f35ac2ec48058a4",
"size": 125719261,
"url": "https://dl.espressif.com/dl/xtensa-esp32-elf-win32-1.22.0-80-g6c4433a-5.2.0.zip"
},
"win64": {
"sha256": "f217fccbeaaa8c92db239036e0d6202458de4488b954a3a38f35ac2ec48058a4",
"size": 125719261,
"url": "https://dl.espressif.com/dl/xtensa-esp32-elf-win32-1.22.0-80-g6c4433a-5.2.0.zip"
}
},
{
"linux-amd64": {
"sha256": "3fe96c151d46c1d4e5edc6ed690851b8e53634041114bad04729bc16b0445156",
"size": 44219107,
"url": "https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz"
},
"linux-i686": {
"sha256": "b4055695ffc2dfc0bcb6dafdc2572a6e01151c4179ef5fa972b3fcb2183eb155",
"size": 45566336,
"url": "https://dl.espressif.com/dl/xtensa-esp32-elf-linux32-1.22.0-80-g6c4433a-5.2.0.tar.gz"
},
"macos": {
"sha256": "a4307a97945d2f2f2745f415fbe80d727750e19f91f9a1e7e2f8a6065652f9da",
"size": 46517409,
"url": "https://dl.espressif.com/dl/xtensa-esp32-elf-osx-1.22.0-80-g6c4433a-5.2.0.tar.gz"
},
"name": "1.22.0-80-g6c4433a-5.2.0",
"status": "recommended"
}
]
},
{
"description": "Toolchain for ESP32 ULP coprocessor",
"export_paths": [
[
"esp32ulp-elf-binutils",
"bin"
]
],
"export_vars": {},
"info_url": "https://github.com/espressif/binutils-esp32ulp",
"install": "always",
"license": "GPL-2.0-or-later",
"name": "esp32ulp-elf",
"version_cmd": [
"esp32ulp-elf-as",
"--version"
],
"version_regex": "\\(GNU Binutils\\)\\s+([0-9a-z\\.\\-]+)",
"versions": [
{
"linux-amd64": {
"sha256": "c1bbcd65e1e30c7312a50344c8dbc70c2941580a79aa8f8abbce8e0e90c79566",
"size": 8246604,
"url": "https://dl.espressif.com/dl/binutils-esp32ulp-linux64-2.28.51-esp32ulp-20180809.tar.gz"
},
"macos": {
"sha256": "c92937d85cc9a90eb6c6099ce767ca021108c18c94e34bd7b1fa0cde168f94a0",
"size": 5726662,
"url": "https://dl.espressif.com/dl/binutils-esp32ulp-macos-2.28.51-esp32ulp-20180809.tar.gz"
},
"name": "2.28.51.20170517",
"status": "recommended",
"win32": {
"sha256": "92dc83e69e534c9f73d7b939088f2e84f757d2478483415d17fe9dd1c236f2fd",
"size": 12231559,
"url": "https://dl.espressif.com/dl/binutils-esp32ulp-win32-2.28.51-esp32ulp-20180809.zip"
},
"win64": {
"sha256": "92dc83e69e534c9f73d7b939088f2e84f757d2478483415d17fe9dd1c236f2fd",
"size": 12231559,
"url": "https://dl.espressif.com/dl/binutils-esp32ulp-win32-2.28.51-esp32ulp-20180809.zip"
}
}
]
},
{
"description": "CMake build system",
"export_paths": [
[
"bin"
]
],
"export_vars": {},
"info_url": "https://github.com/Kitware/CMake",
"install": "on_request",
"license": "BSD-3-Clause",
"name": "cmake",
"platform_overrides": [
{
"install": "always",
"platforms": [
"win32",
"win64"
]
},
{
"export_paths": [
[
"CMake.app",
"Contents",
"bin"
]
],
"platforms": [
"macos"
]
}
],
"strip_container_dirs": 1,
"version_cmd": [
"cmake",
"--version"
],
"version_regex": "cmake version ([0-9.]+)",
"versions": [
{
"linux-amd64": {
"sha256": "563a39e0a7c7368f81bfa1c3aff8b590a0617cdfe51177ddc808f66cc0866c76",
"size": 38405896,
"url": "https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-Linux-x86_64.tar.gz"
},
"macos": {
"sha256": "fef537614d73fda848f6168273b6c7ba45f850484533361e7bc50ac1d315f780",
"size": 32062124,
"url": "https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-Darwin-x86_64.tar.gz"
},
"name": "3.13.4",
"status": "recommended",
"win32": {
"sha256": "28daf772f55d817a13ef14e25af2a5569f8326dac66a6aa3cc5208cf1f8e943f",
"size": 26385104,
"url": "https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-win32-x86.zip"
},
"win64": {
"sha256": "bcd477d49e4a9400b41213d53450b474beaedb264631693c958ef9affa8e5623",
"size": 29696565,
"url": "https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-win64-x64.zip"
}
}
]
},
{
"description": "OpenOCD for ESP32",
"export_paths": [
[
"openocd-esp32",
"bin"
]
],
"export_vars": {
"OPENOCD_SCRIPTS": "${TOOL_PATH}/openocd-esp32/share/openocd/scripts"
},
"info_url": "https://github.com/espressif/openocd-esp32",
"install": "always",
"license": "GPL-2.0-only",
"name": "openocd-esp32",
"version_cmd": [
"openocd",
"--version"
],
"version_regex": "Open On-Chip Debugger\\s+([a-z0-9.-]+)\\s+",
"versions": [
{
"linux-amd64": {
"sha256": "e5b5579edffde090e426b4995b346e281843bf84394f8e68c8e41bd1e4c576bd",
"size": 1681596,
"url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-linux64-0.10.0-esp32-20190313.tar.gz"
},
"macos": {
"sha256": "09504eea5aa92646a117f16573c95b34e04b4010791a2f8fefcd2bd8c430f081",
"size": 1760536,
"url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-macos-0.10.0-esp32-20190313.tar.gz"
},
"name": "v0.10.0-esp32-20190313",
"status": "recommended",
"win32": {
"sha256": "b86a7f9f39dfc4d8e289fc819375bbb7a5e9fcb8895805ba2b5faf67b8b25ce2",
"size": 2098513,
"url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-win32-0.10.0-esp32-20190313.zip"
},
"win64": {
"sha256": "b86a7f9f39dfc4d8e289fc819375bbb7a5e9fcb8895805ba2b5faf67b8b25ce2",
"size": 2098513,
"url": "https://github.com/espressif/openocd-esp32/releases/download/v0.10.0-esp32-20190313/openocd-esp32-win32-0.10.0-esp32-20190313.zip"
}
}
]
},
{
"description": "menuconfig tool",
"export_paths": [
[
""
]
],
"export_vars": {},
"info_url": "https://github.com/espressif/kconfig-frontends",
"install": "never",
"license": "GPL-2.0-only",
"name": "mconf",
"platform_overrides": [
{
"install": "always",
"platforms": [
"win32",
"win64"
]
}
],
"strip_container_dirs": 1,
"version_cmd": [
"mconf-idf",
"-v"
],
"version_regex": "mconf-idf version mconf-([a-z0-9.-]+)-win32",
"versions": [
{
"name": "v4.6.0.0-idf-20190628",
"status": "recommended",
"win32": {
"sha256": "1b8f17f48740ab669c13bd89136e8cc92efe0cd29872f0d6c44148902a2dc40c",
"size": 826114,
"url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190628/mconf-v4.6.0.0-idf-20190628-win32.zip"
},
"win64": {
"sha256": "1b8f17f48740ab669c13bd89136e8cc92efe0cd29872f0d6c44148902a2dc40c",
"size": 826114,
"url": "https://github.com/espressif/kconfig-frontends/releases/download/v4.6.0.0-idf-20190628/mconf-v4.6.0.0-idf-20190628-win32.zip"
}
}
]
},
{
"description": "Ninja build system",
"export_paths": [
[
""
]
],
"export_vars": {},
"info_url": "https://github.com/ninja-build/ninja",
"install": "on_request",
"license": "Apache-2.0",
"name": "ninja",
"platform_overrides": [
{
"install": "always",
"platforms": [
"win32",
"win64"
]
}
],
"version_cmd": [
"ninja",
"--version"
],
"version_regex": "([0-9.]+)",
"versions": [
{
"linux-amd64": {
"sha256": "978fd9e26c2db8d33392c6daef50e9edac0a3db6680710a9f9ad47e01f3e49b7",
"size": 85276,
"url": "https://dl.espressif.com/dl/ninja-1.9.0-linux64.tar.gz"
},
"macos": {
"sha256": "9504cd1783ef3c242d06330a50d54dc8f838b605f5fc3e892c47254929f7350c",
"size": 91457,
"url": "https://dl.espressif.com/dl/ninja-1.9.0-osx.tar.gz"
},
"name": "1.9.0",
"status": "recommended",
"win64": {
"sha256": "2d70010633ddaacc3af4ffbd21e22fae90d158674a09e132e06424ba3ab036e9",
"size": 254497,
"url": "https://dl.espressif.com/dl/ninja-1.9.0-win64.zip"
}
}
]
},
{
"description": "IDF wrapper tool for Windows",
"export_paths": [
[
""
]
],
"export_vars": {},
"info_url": "https://github.com/espressif/esp-idf/tree/master/tools/windows/idf_exe",
"install": "never",
"license": "Apache-2.0",
"name": "idf-exe",
"platform_overrides": [
{
"install": "always",
"platforms": [
"win32",
"win64"
]
}
],
"version_cmd": [
"idf.py.exe",
"-v"
],
"version_regex": "([0-9.]+)",
"versions": [
{
"name": "1.0",
"status": "recommended",
"win32": {
"sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748",
"size": 11289,
"url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip"
},
"win64": {
"sha256": "83a83ac7a246cbae93884db7c5f2ef9a7607d602340b1cf1e64ec2a925071748",
"size": 11289,
"url": "https://dl.espressif.com/dl/idf-exe-v1.0.zip"
}
}
]
},
{
"description": "Ccache (compiler cache)",
"export_paths": [
[
""
]
],
"export_vars": {},
"info_url": "https://github.com/ccache/ccache",
"install": "never",
"license": "GPL-3.0-or-later",
"name": "ccache",
"platform_overrides": [
{
"install": "always",
"platforms": [
"win64"
]
}
],
"version_cmd": [
"ccache.exe",
"--version"
],
"version_regex": "ccache version ([0-9.]+)",
"versions": [
{
"name": "3.7",
"status": "recommended",
"win64": {
"sha256": "37e833f3f354f1145503533e776c1bd44ec2e77ff8a2476a1d2039b0b10c78d6",
"size": 142401,
"url": "https://dl.espressif.com/dl/ccache-3.7-w64.zip"
}
}
]
}
],
"version": 1
}

View file

@ -0,0 +1,157 @@
{ Copyright 2019 Espressif Systems (Shanghai) PTE LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Helper functions from libcmdlinerunner.dll ------------------------------ }
function ProcStart(cmdline, workdir: string): Longword;
external 'proc_start@files:cmdlinerunner.dll cdecl';
function ProcGetExitCode(inst: Longword): DWORD;
external 'proc_get_exit_code@files:cmdlinerunner.dll cdecl';
function ProcGetOutput(inst: Longword; dest: PAnsiChar; sz: DWORD): DWORD;
external 'proc_get_output@files:cmdlinerunner.dll cdecl';
procedure ProcEnd(inst: Longword);
external 'proc_end@files:cmdlinerunner.dll cdecl';
{ ------------------------------ WinAPI functions ------------------------------ }
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
function SetEnvironmentVariable(lpName: string; lpValue: string): BOOL;
external 'SetEnvironmentVariable{#AW}@kernel32.dll stdcall';
{ ------------------------------ Functions to query the registry ------------------------------ }
{ Utility to search in HKLM and HKCU for an installation path. Looks in both 64-bit & 32-bit registry. }
function GetInstallPath(key, valuename : String) : String;
var
value: String;
begin
Result := '';
if RegQueryStringValue(HKEY_LOCAL_MACHINE, key, valuename, value) then
begin
Result := value;
exit;
end;
if RegQueryStringValue(HKEY_CURRENT_USER, key, valuename, value) then
begin
Result := value;
exit;
end;
{ This is 32-bit setup running on 64-bit Windows, but ESP-IDF can use 64-bit tools also }
if IsWin64 and RegQueryStringValue(HKLM64, key, valuename, value) then
begin
Result := value;
exit;
end;
if IsWin64 and RegQueryStringValue(HKCU64, key, valuename, value) then
begin
Result := value;
exit;
end;
end;
{ ------------------------------ Function to exit from the installer ------------------------------ }
procedure AbortInstallation(Message: String);
begin
MsgBox(Message, mbError, MB_OK);
Abort();
end;
{ ------------------------------ File system related functions ------------------------------ }
function DirIsEmpty(DirName: String): Boolean;
var
FindRec: TFindRec;
begin
Result := True;
if FindFirst(DirName+'\*', FindRec) then begin
try
repeat
if (FindRec.Name <> '.') and (FindRec.Name <> '..') then begin
Result := False;
break;
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
type
TFindFileCallback = procedure(Filename: String);
procedure FindFileRecusive(Directory: string; FileName: string; Callback: TFindFileCallback);
var
FindRec: TFindRec;
FilePath: string;
begin
if FindFirst(Directory + '\*', FindRec) then
begin
try
repeat
if (FindRec.Name = '.') or (FindRec.Name = '..') then
continue;
FilePath := Directory + '\' + FindRec.Name;
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
begin
FindFileRecusive(FilePath, FileName, Callback);
end else if CompareText(FindRec.Name, FileName) = 0 then
begin
Callback(FilePath);
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
{ ------------------------------ Version related functions ------------------------------ }
function VersionExtractMajorMinor(Version: String; var Major: Integer; var Minor: Integer): Boolean;
var
Delim: Integer;
MajorStr, MinorStr: String;
OrigVersion, ExpectedPrefix: String;
begin
Result := False;
OrigVersion := Version;
Delim := Pos('.', Version);
if Delim = 0 then exit;
MajorStr := Version;
Delete(MajorStr, Delim, Length(MajorStr));
Delete(Version, 1, Delim);
Major := StrToInt(MajorStr);
Delim := Pos('.', Version);
if Delim = 0 then Delim := Length(MinorStr);
MinorStr := Version;
Delete(MinorStr, Delim, Length(MinorStr));
Delete(Version, 1, Delim);
Minor := StrToInt(MinorStr);
{ Sanity check }
ExpectedPrefix := IntToStr(Major) + '.' + IntToStr(Minor);
if Pos(ExpectedPrefix, OrigVersion) <> 1 then
begin
Log('VersionExtractMajorMinor: version=' + OrigVersion + ', expected=' + ExpectedPrefix);
exit;
end;
Result := True;
end;