27
27
import os
28
28
29
29
import click
30
+ import semantic_version
30
31
31
32
from SCons .Script import (
32
33
ARGUMENTS ,
38
39
from platformio .proc import exec_command
39
40
from platformio .util import get_systype
40
41
from platformio .builder .tools .piolib import ProjectAsLibBuilder
41
- from platformio .package .version import get_original_version
42
+ from platformio .package .version import get_original_version , pepver_to_semver
42
43
43
44
env = DefaultEnvironment ()
44
45
env .SConscript ("_embed_files.py" , exports = "env" )
68
69
assert ARDUINO_FRAMEWORK_DIR and os .path .isdir (ARDUINO_FRAMEWORK_DIR )
69
70
70
71
BUILD_DIR = env .subst ("$BUILD_DIR" )
72
+ PROJECT_DIR = env .subst ("$PROJECT_DIR" )
73
+ PROJECT_SRC_DIR = env .subst ("$PROJECT_SRC_DIR" )
71
74
CMAKE_API_REPLY_PATH = os .path .join (".cmake" , "api" , "v1" , "reply" )
72
75
73
- try :
74
- import future
75
- import pyparsing
76
- import cryptography
77
- except ImportError :
78
- env .Execute (
79
- env .VerboseAction (
80
- '$PYTHONEXE -m pip install "cryptography>=2.1.4" "future>=0.15.2" "pyparsing>=2.0.3,<2.4.0" ' ,
81
- "Installing ESP-IDF's Python dependencies" ,
82
- )
83
- )
84
-
85
- # a special "esp-windows-curses" python package is required on Windows for Menuconfig
86
- if "windows" in get_systype ():
87
- import pkg_resources
88
-
89
- if "esp-windows-curses" not in {pkg .key for pkg in pkg_resources .working_set }:
90
- env .Execute (
91
- env .VerboseAction (
92
- '$PYTHONEXE -m pip install "file://%s/tools/kconfig_new/esp-windows-curses" windows-curses'
93
- % FRAMEWORK_DIR ,
94
- "Installing windows-curses package" ,
95
- )
96
- )
97
-
98
76
99
77
def get_project_lib_includes (env ):
100
78
project = ProjectAsLibBuilder (env , "$PROJECT_DIR" )
@@ -116,11 +94,11 @@ def get_project_lib_includes(env):
116
94
def is_cmake_reconfigure_required (cmake_api_reply_dir ):
117
95
cmake_cache_file = os .path .join (BUILD_DIR , "CMakeCache.txt" )
118
96
cmake_txt_files = [
119
- os .path .join (env . subst ( "$ PROJECT_DIR" ) , "CMakeLists.txt" ),
120
- os .path .join (env . subst ( "$ PROJECT_SRC_DIR" ) , "CMakeLists.txt" ),
97
+ os .path .join (PROJECT_DIR , "CMakeLists.txt" ),
98
+ os .path .join (PROJECT_SRC_DIR , "CMakeLists.txt" ),
121
99
]
122
100
cmake_preconf_dir = os .path .join (BUILD_DIR , "config" )
123
- sdkconfig = os .path .join (env . subst ( "$ PROJECT_DIR" ) , "sdkconfig" )
101
+ sdkconfig = os .path .join (PROJECT_DIR , "sdkconfig" )
124
102
125
103
for d in (cmake_api_reply_dir , cmake_preconf_dir ):
126
104
if not os .path .isdir (d ) or not os .listdir (d ):
@@ -146,8 +124,8 @@ def is_proper_idf_project():
146
124
return all (
147
125
os .path .isfile (path )
148
126
for path in (
149
- os .path .join (env . subst ( "$ PROJECT_DIR" ) , "CMakeLists.txt" ),
150
- os .path .join (env . subst ( "$ PROJECT_SRC_DIR" ) , "CMakeLists.txt" ),
127
+ os .path .join (PROJECT_DIR , "CMakeLists.txt" ),
128
+ os .path .join (PROJECT_SRC_DIR , "CMakeLists.txt" ),
151
129
)
152
130
)
153
131
@@ -161,9 +139,8 @@ def collect_src_files():
161
139
162
140
163
141
def normalize_path (path ):
164
- project_dir = env .subst ("$PROJECT_DIR" )
165
- if project_dir in path :
166
- path = path .replace (project_dir , "${CMAKE_SOURCE_DIR}" )
142
+ if PROJECT_DIR in path :
143
+ path = path .replace (PROJECT_DIR , "${CMAKE_SOURCE_DIR}" )
167
144
return fs .to_unix_path (path )
168
145
169
146
@@ -180,20 +157,20 @@ def create_default_project_files():
180
157
idf_component_register(SRCS ${app_sources})
181
158
"""
182
159
183
- if not os .listdir (os . path . join ( env . subst ( "$ PROJECT_SRC_DIR" )) ):
160
+ if not os .listdir (PROJECT_SRC_DIR ):
184
161
# create a default main file to make CMake happy during first init
185
- with open (os .path .join (env . subst ( "$ PROJECT_SRC_DIR" ) , "main.c" ), "w" ) as fp :
162
+ with open (os .path .join (PROJECT_SRC_DIR , "main.c" ), "w" ) as fp :
186
163
fp .write ("void app_main() {}" )
187
164
188
- project_dir = env . subst ( "$ PROJECT_DIR" )
165
+ project_dir = PROJECT_DIR
189
166
if not os .path .isfile (os .path .join (project_dir , "CMakeLists.txt" )):
190
167
with open (os .path .join (project_dir , "CMakeLists.txt" ), "w" ) as fp :
191
168
fp .write (root_cmake_tpl % os .path .basename (project_dir ))
192
169
193
- project_src_dir = env . subst ( "$ PROJECT_SRC_DIR" )
170
+ project_src_dir = PROJECT_SRC_DIR
194
171
if not os .path .isfile (os .path .join (project_src_dir , "CMakeLists.txt" )):
195
172
with open (os .path .join (project_src_dir , "CMakeLists.txt" ), "w" ) as fp :
196
- fp .write (prj_cmake_tpl % normalize_path (env . subst ( "$ PROJECT_SRC_DIR" ) ))
173
+ fp .write (prj_cmake_tpl % normalize_path (PROJECT_SRC_DIR ))
197
174
198
175
199
176
def get_cmake_code_model (src_dir , build_dir , extra_args = None ):
@@ -431,7 +408,9 @@ def find_framework_service_files(search_path, sdk_config):
431
408
continue
432
409
for f in os .listdir (path ):
433
410
# Skip hardware specific files as they will be added later
434
- if f == "linker.lf" and not os .path .basename (path ).startswith ("esp32" ):
411
+ if f == "linker.lf" and not os .path .basename (path ).startswith (
412
+ ("esp32" , "riscv" )
413
+ ):
435
414
result ["lf_files" ].append (os .path .join (path , f ))
436
415
elif f == "Kconfig.projbuild" :
437
416
result ["kconfig_build_files" ].append (os .path .join (path , f ))
@@ -506,7 +485,7 @@ def generate_project_ld_script(sdk_config, ignore_targets=None):
506
485
507
486
args = {
508
487
"script" : os .path .join (FRAMEWORK_DIR , "tools" , "ldgen" , "ldgen.py" ),
509
- "config" : os .path .join (env . subst ( "$ PROJECT_DIR" ) , "sdkconfig" ),
488
+ "config" : os .path .join (PROJECT_DIR , "sdkconfig" ),
510
489
"fragments" : " " .join (['"%s"' % f for f in project_files .get ("lf_files" )]),
511
490
"kconfig" : os .path .join (FRAMEWORK_DIR , "Kconfig" ),
512
491
"env_file" : os .path .join ("$BUILD_DIR" , "config.env" ),
@@ -704,7 +683,7 @@ def build_bootloader():
704
683
"-DPYTHON_DEPS_CHECKED=1" ,
705
684
"-DPYTHON=" + env .subst ("$PYTHONEXE" ),
706
685
"-DIDF_PATH=" + FRAMEWORK_DIR ,
707
- "-DSDKCONFIG=" + os .path .join (env . subst ( "$ PROJECT_DIR" ) , "sdkconfig" ),
686
+ "-DSDKCONFIG=" + os .path .join (PROJECT_DIR , "sdkconfig" ),
708
687
"-DLEGACY_INCLUDE_COMMON_HEADERS=" ,
709
688
"-DEXTRA_COMPONENT_DIRS="
710
689
+ os .path .join (FRAMEWORK_DIR , "components" , "bootloader" ),
@@ -983,7 +962,7 @@ def generate_mbedtls_bundle(sdk_config):
983
962
crt_args .append ("-q" )
984
963
985
964
# Use exec_command to change working directory
986
- exec_command (cmd + crt_args , cwd = env . subst ( "$ BUILD_DIR" ) )
965
+ exec_command (cmd + crt_args , cwd = BUILD_DIR )
987
966
bundle_path = os .path .join ("$BUILD_DIR" , "x509_crt_bundle" )
988
967
env .Execute (
989
968
env .VerboseAction (
@@ -1012,6 +991,72 @@ def generate_mbedtls_bundle(sdk_config):
1012
991
)
1013
992
1014
993
994
+ def install_python_deps ():
995
+ def _get_installed_pip_packages ():
996
+ result = {}
997
+ packages = {}
998
+ pip_output = subprocess .check_output (
999
+ [env .subst ("$PYTHONEXE" ), "-m" , "pip" , "list" , "--format=json" ]
1000
+ )
1001
+ try :
1002
+ packages = json .loads (pip_output )
1003
+ except :
1004
+ print ("Warning! Couldn't extract the list of installed Python packages." )
1005
+ return {}
1006
+ for p in packages :
1007
+ result [p ["name" ]] = pepver_to_semver (p ["version" ])
1008
+
1009
+ return result
1010
+
1011
+ deps = {
1012
+ "cryptography" : ">=2.1.4" ,
1013
+ "future" : ">=0.15.2" ,
1014
+ "pyparsing" : ">=2.0.3,<2.4.0" ,
1015
+ "kconfiglib" : "==13.7.1" ,
1016
+ }
1017
+
1018
+ installed_packages = _get_installed_pip_packages ()
1019
+ packages_to_install = []
1020
+ for package , spec in deps .items ():
1021
+ if package not in installed_packages :
1022
+ packages_to_install .append (package )
1023
+ else :
1024
+ version_spec = semantic_version .Spec (spec )
1025
+ if not version_spec .match (installed_packages [package ]):
1026
+ packages_to_install .append (package )
1027
+
1028
+ if packages_to_install :
1029
+ env .Execute (
1030
+ env .VerboseAction (
1031
+ (
1032
+ '"$PYTHONEXE" -m pip install -U --force-reinstall '
1033
+ + " " .join (['"%s%s"' % (p , deps [p ]) for p in packages_to_install ])
1034
+ ),
1035
+ "Installing ESP-IDF's Python dependencies" ,
1036
+ )
1037
+ )
1038
+
1039
+ # a special "esp-windows-curses" python package is required on Windows for Menuconfig
1040
+ if "windows" in get_systype ():
1041
+ import pkg_resources
1042
+
1043
+ if "esp-windows-curses" not in {pkg .key for pkg in pkg_resources .working_set }:
1044
+ env .Execute (
1045
+ env .VerboseAction (
1046
+ '$PYTHONEXE -m pip install "file://%s/tools/kconfig_new/esp-windows-curses" windows-curses'
1047
+ % FRAMEWORK_DIR ,
1048
+ "Installing windows-curses package" ,
1049
+ )
1050
+ )
1051
+
1052
+
1053
+ #
1054
+ # ESP-IDF requires Python packages with specific versions
1055
+ #
1056
+
1057
+ install_python_deps ()
1058
+
1059
+
1015
1060
# ESP-IDF package doesn't contain .git folder, instead package version is specified
1016
1061
# in a special file "version.h" in the root folder of the package
1017
1062
@@ -1079,6 +1124,12 @@ def generate_mbedtls_bundle(sdk_config):
1079
1124
sys .stderr .write ("Error: Detected a whitespace character in project paths.\n " )
1080
1125
env .Exit (1 )
1081
1126
1127
+ if not os .path .isdir (PROJECT_SRC_DIR ):
1128
+ sys .stderr .write (
1129
+ "Error: Missing the `%s` folder with project sources.\n "
1130
+ % os .path .basename (PROJECT_SRC_DIR )
1131
+ )
1132
+ env .Exit (1 )
1082
1133
1083
1134
if env .subst ("$SRC_FILTER" ):
1084
1135
print (
@@ -1088,7 +1139,7 @@ def generate_mbedtls_bundle(sdk_config):
1088
1139
)
1089
1140
)
1090
1141
1091
- if os .path .isfile (os .path .join (env . subst ( "$ PROJECT_SRC_DIR" ) , "sdkconfig.h" )):
1142
+ if os .path .isfile (os .path .join (PROJECT_SRC_DIR , "sdkconfig.h" )):
1092
1143
print (
1093
1144
"Warning! Starting with ESP-IDF v4.0, new project structure is required: \n "
1094
1145
"https://docs.platformio.org/en/latest/frameworks/espidf.html#project-structure"
@@ -1102,16 +1153,18 @@ def generate_mbedtls_bundle(sdk_config):
1102
1153
# default 'src' folder we need to add this as an extra component. If there is no 'main'
1103
1154
# folder CMake won't generate dependencies properly
1104
1155
extra_components = [generate_default_component ()]
1105
- if env .subst ("$PROJECT_SRC_DIR" ) != os .path .join (env .subst ("$PROJECT_DIR" ), "main" ):
1106
- extra_components .append (env .subst ("$PROJECT_SRC_DIR" ))
1107
- if "arduino" in env .subst ("$PIOFRAMEWORK" ):
1108
- print ("Warning! Arduino framework as an ESP-IDF component doesn't handle "
1109
- "the `variant` field! The default `esp32` variant will be used." )
1110
- extra_components .append (ARDUINO_FRAMEWORK_DIR )
1156
+ if PROJECT_SRC_DIR != os .path .join (PROJECT_DIR , "main" ):
1157
+ extra_components .append (PROJECT_SRC_DIR )
1158
+ if "arduino" in env .subst ("$PIOFRAMEWORK" ):
1159
+ print (
1160
+ "Warning! Arduino framework as an ESP-IDF component doesn't handle "
1161
+ "the `variant` field! The default `esp32` variant will be used."
1162
+ )
1163
+ extra_components .append (ARDUINO_FRAMEWORK_DIR )
1111
1164
1112
1165
print ("Reading CMake configuration..." )
1113
1166
project_codemodel = get_cmake_code_model (
1114
- env . subst ( "$ PROJECT_DIR" ) ,
1167
+ PROJECT_DIR ,
1115
1168
BUILD_DIR ,
1116
1169
[
1117
1170
"-DIDF_TARGET=" + idf_variant ,
@@ -1132,7 +1185,7 @@ def generate_mbedtls_bundle(sdk_config):
1132
1185
1133
1186
sdk_config = get_sdk_configuration ()
1134
1187
1135
- project_target_name = "__idf_%s" % os .path .basename (env . subst ( "$ PROJECT_SRC_DIR" ) )
1188
+ project_target_name = "__idf_%s" % os .path .basename (PROJECT_SRC_DIR )
1136
1189
if project_target_name not in target_configs :
1137
1190
sys .stderr .write ("Error: Couldn't find the main target of the project!\n " )
1138
1191
env .Exit (1 )
@@ -1160,7 +1213,7 @@ def generate_mbedtls_bundle(sdk_config):
1160
1213
[project_target_name , default_config_name ],
1161
1214
)
1162
1215
1163
- build_components (env , framework_components_map , env . subst ( "$ PROJECT_DIR" ) )
1216
+ build_components (env , framework_components_map , PROJECT_DIR )
1164
1217
1165
1218
if not elf_config :
1166
1219
sys .stderr .write ("Error: Couldn't load the main firmware target of the project\n " )
@@ -1223,12 +1276,7 @@ def generate_mbedtls_bundle(sdk_config):
1223
1276
# Remove project source files from following build stages as they're
1224
1277
# built as part of the framework
1225
1278
def _skip_prj_source_files (node ):
1226
- if (
1227
- node .srcnode ()
1228
- .get_path ()
1229
- .lower ()
1230
- .startswith (env .subst ("$PROJECT_SRC_DIR" ).lower ())
1231
- ):
1279
+ if node .srcnode ().get_path ().lower ().startswith (PROJECT_SRC_DIR .lower ()):
1232
1280
return None
1233
1281
return node
1234
1282
@@ -1281,16 +1329,6 @@ def _skip_prj_source_files(node):
1281
1329
],
1282
1330
)
1283
1331
1284
- # USB stack for ESP32-S2 is implemented using tinyusb library. In IDF v4.2 it's added as
1285
- # an INTERFACE library which means that CMake doesn't export build information for it
1286
- # in File-API hence it's not present in components map. As a workaround we can build
1287
- # the lib using project build environment with additional flags from CMakeLists.txt
1288
- if (
1289
- sdk_config .get ("USB_ENABLED" , False )
1290
- and "__idf_tinyusb" not in framework_components_map
1291
- ):
1292
- build_tinyusb_lib (env )
1293
-
1294
1332
#
1295
1333
# Generate mbedtls bundle
1296
1334
#
@@ -1312,7 +1350,7 @@ def _skip_prj_source_files(node):
1312
1350
# Compile ULP sources in 'ulp' folder
1313
1351
#
1314
1352
1315
- ulp_dir = os .path .join (env . subst ( "$ PROJECT_DIR" ) , "ulp" )
1353
+ ulp_dir = os .path .join (PROJECT_DIR , "ulp" )
1316
1354
if os .path .isdir (ulp_dir ) and os .listdir (ulp_dir ):
1317
1355
env .SConscript ("ulp.py" , exports = "env project_config idf_variant" )
1318
1356
0 commit comments