David Ghandehari | 8c5039b | 2016-08-17 19:39:30 -0700 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | ## |
| 3 | ## Copyright (c) 2013 The WebM project authors. All Rights Reserved. |
| 4 | ## |
| 5 | ## Use of this source code is governed by a BSD-style license |
| 6 | ## that can be found in the LICENSE file in the root of the source |
| 7 | ## tree. An additional intellectual property rights grant can be found |
| 8 | ## in the file PATENTS. All contributing project authors may |
| 9 | ## be found in the AUTHORS file in the root of the source tree. |
| 10 | ## |
| 11 | |
| 12 | self=$0 |
| 13 | self_basename=${self##*/} |
| 14 | self_dirname=$(dirname "$0") |
| 15 | |
| 16 | . "$self_dirname/msvs_common.sh"|| exit 127 |
| 17 | |
| 18 | show_help() { |
| 19 | cat <<EOF |
| 20 | Usage: ${self_basename} --name=projname [options] file1 [file2 ...] |
| 21 | |
| 22 | This script generates a Visual Studio project file from a list of source |
| 23 | code files. |
| 24 | |
| 25 | Options: |
| 26 | --help Print this message |
| 27 | --exe Generate a project for building an Application |
| 28 | --lib Generate a project for creating a static library |
| 29 | --dll Generate a project for creating a dll |
| 30 | --static-crt Use the static C runtime (/MT) |
| 31 | --enable-werror Treat warnings as errors (/WX) |
| 32 | --target=isa-os-cc Target specifier (required) |
| 33 | --out=filename Write output to a file [stdout] |
| 34 | --name=project_name Name of the project (required) |
| 35 | --proj-guid=GUID GUID to use for the project |
| 36 | --module-def=filename File containing export definitions (for DLLs) |
| 37 | --ver=version Version (10,11,12,14) of visual studio to generate for |
| 38 | --src-path-bare=dir Path to root of source tree |
| 39 | -Ipath/to/include Additional include directories |
| 40 | -DFLAG[=value] Preprocessor macros to define |
| 41 | -Lpath/to/lib Additional library search paths |
| 42 | -llibname Library to link against |
| 43 | EOF |
| 44 | exit 1 |
| 45 | } |
| 46 | |
| 47 | tag_content() { |
| 48 | local tag=$1 |
| 49 | local content=$2 |
| 50 | shift |
| 51 | shift |
| 52 | if [ $# -ne 0 ]; then |
| 53 | echo "${indent}<${tag}" |
| 54 | indent_push |
| 55 | tag_attributes "$@" |
| 56 | echo "${indent}>${content}</${tag}>" |
| 57 | indent_pop |
| 58 | else |
| 59 | echo "${indent}<${tag}>${content}</${tag}>" |
| 60 | fi |
| 61 | } |
| 62 | |
| 63 | generate_filter() { |
| 64 | local name=$1 |
| 65 | local pats=$2 |
| 66 | local file_list_sz |
| 67 | local i |
| 68 | local f |
| 69 | local saveIFS="$IFS" |
| 70 | local pack |
| 71 | echo "generating filter '$name' from ${#file_list[@]} files" >&2 |
| 72 | IFS=* |
| 73 | |
| 74 | file_list_sz=${#file_list[@]} |
| 75 | for i in ${!file_list[@]}; do |
| 76 | f=${file_list[i]} |
| 77 | for pat in ${pats//;/$IFS}; do |
| 78 | if [ "${f##*.}" == "$pat" ]; then |
| 79 | unset file_list[i] |
| 80 | |
| 81 | objf=$(echo ${f%.*}.obj \ |
| 82 | | sed -e "s,$src_path_bare,," \ |
| 83 | -e 's/^[\./]\+//g' -e 's,[:/ ],_,g') |
| 84 | |
| 85 | if ([ "$pat" == "asm" ] || [ "$pat" == "s" ]) && $asm_use_custom_step; then |
| 86 | # Avoid object file name collisions, i.e. vpx_config.c and |
| 87 | # vpx_config.asm produce the same object file without |
| 88 | # this additional suffix. |
| 89 | objf=${objf%.obj}_asm.obj |
| 90 | open_tag CustomBuild \ |
| 91 | Include="$f" |
| 92 | for plat in "${platforms[@]}"; do |
| 93 | for cfg in Debug Release; do |
| 94 | tag_content Message "Assembling %(Filename)%(Extension)" \ |
| 95 | Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'" |
| 96 | tag_content Command "$(eval echo \$asm_${cfg}_cmdline) -o \$(IntDir)$objf" \ |
| 97 | Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'" |
| 98 | tag_content Outputs "\$(IntDir)$objf" \ |
| 99 | Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'" |
| 100 | done |
| 101 | done |
| 102 | close_tag CustomBuild |
| 103 | elif [ "$pat" == "c" ] || \ |
| 104 | [ "$pat" == "cc" ] || [ "$pat" == "cpp" ]; then |
| 105 | open_tag ClCompile \ |
| 106 | Include="$f" |
| 107 | # Separate file names with Condition? |
| 108 | tag_content ObjectFileName "\$(IntDir)$objf" |
| 109 | # Check for AVX and turn it on to avoid warnings. |
| 110 | if [[ $f =~ avx.?\.c$ ]]; then |
| 111 | tag_content AdditionalOptions "/arch:AVX" |
| 112 | fi |
| 113 | close_tag ClCompile |
| 114 | elif [ "$pat" == "h" ] ; then |
| 115 | tag ClInclude \ |
| 116 | Include="$f" |
| 117 | elif [ "$pat" == "vcxproj" ] ; then |
| 118 | open_tag ProjectReference \ |
| 119 | Include="$f" |
| 120 | depguid=`grep ProjectGuid "$f" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'` |
| 121 | tag_content Project "$depguid" |
| 122 | tag_content ReferenceOutputAssembly false |
| 123 | close_tag ProjectReference |
| 124 | else |
| 125 | tag None \ |
| 126 | Include="$f" |
| 127 | fi |
| 128 | |
| 129 | break |
| 130 | fi |
| 131 | done |
| 132 | done |
| 133 | |
| 134 | IFS="$saveIFS" |
| 135 | } |
| 136 | |
| 137 | # Process command line |
| 138 | unset target |
| 139 | for opt in "$@"; do |
| 140 | optval="${opt#*=}" |
| 141 | case "$opt" in |
| 142 | --help|-h) show_help |
| 143 | ;; |
| 144 | --target=*) target="${optval}" |
| 145 | ;; |
| 146 | --out=*) outfile="$optval" |
| 147 | ;; |
| 148 | --name=*) name="${optval}" |
| 149 | ;; |
| 150 | --proj-guid=*) guid="${optval}" |
| 151 | ;; |
| 152 | --module-def=*) module_def="${optval}" |
| 153 | ;; |
| 154 | --exe) proj_kind="exe" |
| 155 | ;; |
| 156 | --dll) proj_kind="dll" |
| 157 | ;; |
| 158 | --lib) proj_kind="lib" |
| 159 | ;; |
| 160 | --src-path-bare=*) |
| 161 | src_path_bare=$(fix_path "$optval") |
| 162 | src_path_bare=${src_path_bare%/} |
| 163 | ;; |
| 164 | --static-crt) use_static_runtime=true |
| 165 | ;; |
| 166 | --enable-werror) werror=true |
| 167 | ;; |
| 168 | --ver=*) |
| 169 | vs_ver="$optval" |
| 170 | case "$optval" in |
| 171 | 10|11|12|14) |
| 172 | ;; |
| 173 | *) die Unrecognized Visual Studio Version in $opt |
| 174 | ;; |
| 175 | esac |
| 176 | ;; |
| 177 | -I*) |
| 178 | opt=${opt##-I} |
| 179 | opt=$(fix_path "$opt") |
| 180 | opt="${opt%/}" |
| 181 | incs="${incs}${incs:+;}"${opt}"" |
| 182 | yasmincs="${yasmincs} -I"${opt}"" |
| 183 | ;; |
| 184 | -D*) defines="${defines}${defines:+;}${opt##-D}" |
| 185 | ;; |
| 186 | -L*) # fudge . to $(OutDir) |
| 187 | if [ "${opt##-L}" == "." ]; then |
| 188 | libdirs="${libdirs}${libdirs:+;}"\$(OutDir)"" |
| 189 | else |
| 190 | # Also try directories for this platform/configuration |
| 191 | opt=${opt##-L} |
| 192 | opt=$(fix_path "$opt") |
| 193 | libdirs="${libdirs}${libdirs:+;}"${opt}"" |
| 194 | libdirs="${libdirs}${libdirs:+;}"${opt}/\$(PlatformName)/\$(Configuration)"" |
| 195 | libdirs="${libdirs}${libdirs:+;}"${opt}/\$(PlatformName)"" |
| 196 | fi |
| 197 | ;; |
| 198 | -l*) libs="${libs}${libs:+ }${opt##-l}.lib" |
| 199 | ;; |
| 200 | -*) die_unknown $opt |
| 201 | ;; |
| 202 | *) |
| 203 | # The paths in file_list are fixed outside of the loop. |
| 204 | file_list[${#file_list[@]}]="$opt" |
| 205 | case "$opt" in |
| 206 | *.asm|*.s) uses_asm=true |
| 207 | ;; |
| 208 | esac |
| 209 | ;; |
| 210 | esac |
| 211 | done |
| 212 | |
| 213 | # Make one call to fix_path for file_list to improve performance. |
| 214 | fix_file_list file_list |
| 215 | |
| 216 | outfile=${outfile:-/dev/stdout} |
| 217 | guid=${guid:-`generate_uuid`} |
| 218 | asm_use_custom_step=false |
| 219 | uses_asm=${uses_asm:-false} |
| 220 | case "${vs_ver:-11}" in |
| 221 | 10|11|12|14) |
| 222 | asm_use_custom_step=$uses_asm |
| 223 | ;; |
| 224 | esac |
| 225 | |
| 226 | [ -n "$name" ] || die "Project name (--name) must be specified!" |
| 227 | [ -n "$target" ] || die "Target (--target) must be specified!" |
| 228 | |
| 229 | if ${use_static_runtime:-false}; then |
| 230 | release_runtime=MultiThreaded |
| 231 | debug_runtime=MultiThreadedDebug |
| 232 | lib_sfx=mt |
| 233 | else |
| 234 | release_runtime=MultiThreadedDLL |
| 235 | debug_runtime=MultiThreadedDebugDLL |
| 236 | lib_sfx=md |
| 237 | fi |
| 238 | |
| 239 | # Calculate debug lib names: If a lib ends in ${lib_sfx}.lib, then rename |
| 240 | # it to ${lib_sfx}d.lib. This precludes linking to release libs from a |
| 241 | # debug exe, so this may need to be refactored later. |
| 242 | for lib in ${libs}; do |
| 243 | if [ "$lib" != "${lib%${lib_sfx}.lib}" ]; then |
| 244 | lib=${lib%.lib}d.lib |
| 245 | fi |
| 246 | debug_libs="${debug_libs}${debug_libs:+ }${lib}" |
| 247 | done |
| 248 | debug_libs=${debug_libs// /;} |
| 249 | libs=${libs// /;} |
| 250 | |
| 251 | |
| 252 | # List of all platforms supported for this target |
| 253 | case "$target" in |
| 254 | x86_64*) |
| 255 | platforms[0]="x64" |
| 256 | asm_Debug_cmdline="yasm -Xvc -g cv8 -f win64 ${yasmincs} "%(FullPath)"" |
| 257 | asm_Release_cmdline="yasm -Xvc -f win64 ${yasmincs} "%(FullPath)"" |
| 258 | ;; |
| 259 | x86*) |
| 260 | platforms[0]="Win32" |
| 261 | asm_Debug_cmdline="yasm -Xvc -g cv8 -f win32 ${yasmincs} "%(FullPath)"" |
| 262 | asm_Release_cmdline="yasm -Xvc -f win32 ${yasmincs} "%(FullPath)"" |
| 263 | ;; |
| 264 | arm*) |
| 265 | platforms[0]="ARM" |
| 266 | asm_Debug_cmdline="armasm -nologo -oldit "%(FullPath)"" |
| 267 | asm_Release_cmdline="armasm -nologo -oldit "%(FullPath)"" |
| 268 | ;; |
| 269 | *) die "Unsupported target $target!" |
| 270 | ;; |
| 271 | esac |
| 272 | |
| 273 | generate_vcxproj() { |
| 274 | echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" |
| 275 | open_tag Project \ |
| 276 | DefaultTargets="Build" \ |
| 277 | ToolsVersion="4.0" \ |
| 278 | xmlns="http://schemas.microsoft.com/developer/msbuild/2003" \ |
| 279 | |
| 280 | open_tag ItemGroup \ |
| 281 | Label="ProjectConfigurations" |
| 282 | for plat in "${platforms[@]}"; do |
| 283 | for config in Debug Release; do |
| 284 | open_tag ProjectConfiguration \ |
| 285 | Include="$config|$plat" |
| 286 | tag_content Configuration $config |
| 287 | tag_content Platform $plat |
| 288 | close_tag ProjectConfiguration |
| 289 | done |
| 290 | done |
| 291 | close_tag ItemGroup |
| 292 | |
| 293 | open_tag PropertyGroup \ |
| 294 | Label="Globals" |
| 295 | tag_content ProjectGuid "{${guid}}" |
| 296 | tag_content RootNamespace ${name} |
| 297 | tag_content Keyword ManagedCProj |
| 298 | if [ $vs_ver -ge 12 ] && [ "${platforms[0]}" = "ARM" ]; then |
| 299 | tag_content AppContainerApplication true |
| 300 | # The application type can be one of "Windows Store", |
| 301 | # "Windows Phone" or "Windows Phone Silverlight". The |
| 302 | # actual value doesn't matter from the libvpx point of view, |
| 303 | # since a static library built for one works on the others. |
| 304 | # The PlatformToolset field needs to be set in sync with this; |
| 305 | # for Windows Store and Windows Phone Silverlight it should be |
| 306 | # v120 while it should be v120_wp81 if the type is Windows Phone. |
| 307 | tag_content ApplicationType "Windows Store" |
| 308 | tag_content ApplicationTypeRevision 8.1 |
| 309 | fi |
| 310 | close_tag PropertyGroup |
| 311 | |
| 312 | tag Import \ |
| 313 | Project="\$(VCTargetsPath)\\Microsoft.Cpp.Default.props" |
| 314 | |
| 315 | for plat in "${platforms[@]}"; do |
| 316 | for config in Release Debug; do |
| 317 | open_tag PropertyGroup \ |
| 318 | Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'" \ |
| 319 | Label="Configuration" |
| 320 | if [ "$proj_kind" = "exe" ]; then |
| 321 | tag_content ConfigurationType Application |
| 322 | elif [ "$proj_kind" = "dll" ]; then |
| 323 | tag_content ConfigurationType DynamicLibrary |
| 324 | else |
| 325 | tag_content ConfigurationType StaticLibrary |
| 326 | fi |
| 327 | if [ "$vs_ver" = "11" ]; then |
| 328 | if [ "$plat" = "ARM" ]; then |
| 329 | # Setting the wp80 toolchain automatically sets the |
| 330 | # WINAPI_FAMILY define, which is required for building |
| 331 | # code for arm with the windows headers. Alternatively, |
| 332 | # one could add AppContainerApplication=true in the Globals |
| 333 | # section and add PrecompiledHeader=NotUsing and |
| 334 | # CompileAsWinRT=false in ClCompile and SubSystem=Console |
| 335 | # in Link. |
| 336 | tag_content PlatformToolset v110_wp80 |
| 337 | else |
| 338 | tag_content PlatformToolset v110 |
| 339 | fi |
| 340 | fi |
| 341 | if [ "$vs_ver" = "12" ]; then |
| 342 | # Setting a PlatformToolset indicating windows phone isn't |
| 343 | # enough to build code for arm with MSVC 2013, one strictly |
| 344 | # has to enable AppContainerApplication as well. |
| 345 | tag_content PlatformToolset v120 |
| 346 | fi |
| 347 | if [ "$vs_ver" = "14" ]; then |
| 348 | tag_content PlatformToolset v140 |
| 349 | fi |
| 350 | tag_content CharacterSet Unicode |
| 351 | if [ "$config" = "Release" ]; then |
| 352 | tag_content WholeProgramOptimization true |
| 353 | fi |
| 354 | close_tag PropertyGroup |
| 355 | done |
| 356 | done |
| 357 | |
| 358 | tag Import \ |
| 359 | Project="\$(VCTargetsPath)\\Microsoft.Cpp.props" |
| 360 | |
| 361 | open_tag ImportGroup \ |
| 362 | Label="PropertySheets" |
| 363 | tag Import \ |
| 364 | Project="\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props" \ |
| 365 | Condition="exists('\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props')" \ |
| 366 | Label="LocalAppDataPlatform" |
| 367 | close_tag ImportGroup |
| 368 | |
| 369 | tag PropertyGroup \ |
| 370 | Label="UserMacros" |
| 371 | |
| 372 | for plat in "${platforms[@]}"; do |
| 373 | plat_no_ws=`echo $plat | sed 's/[^A-Za-z0-9_]/_/g'` |
| 374 | for config in Debug Release; do |
| 375 | open_tag PropertyGroup \ |
| 376 | Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'" |
| 377 | tag_content OutDir "\$(SolutionDir)$plat_no_ws\\\$(Configuration)\\" |
| 378 | tag_content IntDir "$plat_no_ws\\\$(Configuration)\\${name}\\" |
| 379 | if [ "$proj_kind" == "lib" ]; then |
| 380 | if [ "$config" == "Debug" ]; then |
| 381 | config_suffix=d |
| 382 | else |
| 383 | config_suffix="" |
| 384 | fi |
| 385 | tag_content TargetName "${name}${lib_sfx}${config_suffix}" |
| 386 | fi |
| 387 | close_tag PropertyGroup |
| 388 | done |
| 389 | done |
| 390 | |
| 391 | for plat in "${platforms[@]}"; do |
| 392 | for config in Debug Release; do |
| 393 | open_tag ItemDefinitionGroup \ |
| 394 | Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'" |
| 395 | if [ "$name" == "vpx" ]; then |
| 396 | hostplat=$plat |
| 397 | if [ "$hostplat" == "ARM" ]; then |
| 398 | hostplat=Win32 |
| 399 | fi |
| 400 | fi |
| 401 | open_tag ClCompile |
| 402 | if [ "$config" = "Debug" ]; then |
| 403 | opt=Disabled |
| 404 | runtime=$debug_runtime |
| 405 | curlibs=$debug_libs |
| 406 | debug=_DEBUG |
| 407 | else |
| 408 | opt=MaxSpeed |
| 409 | runtime=$release_runtime |
| 410 | curlibs=$libs |
| 411 | tag_content FavorSizeOrSpeed Speed |
| 412 | debug=NDEBUG |
| 413 | fi |
| 414 | extradefines=";$defines" |
| 415 | tag_content Optimization $opt |
| 416 | tag_content AdditionalIncludeDirectories "$incs;%(AdditionalIncludeDirectories)" |
| 417 | tag_content PreprocessorDefinitions "WIN32;$debug;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE$extradefines;%(PreprocessorDefinitions)" |
| 418 | tag_content RuntimeLibrary $runtime |
| 419 | tag_content WarningLevel Level3 |
| 420 | if ${werror:-false}; then |
| 421 | tag_content TreatWarningAsError true |
| 422 | fi |
| 423 | if [ $vs_ver -ge 11 ]; then |
| 424 | # We need to override the defaults for these settings |
| 425 | # if AppContainerApplication is set. |
| 426 | tag_content CompileAsWinRT false |
| 427 | tag_content PrecompiledHeader NotUsing |
| 428 | tag_content SDLCheck false |
| 429 | fi |
| 430 | close_tag ClCompile |
| 431 | case "$proj_kind" in |
| 432 | exe) |
| 433 | open_tag Link |
| 434 | tag_content GenerateDebugInformation true |
| 435 | # Console is the default normally, but if |
| 436 | # AppContainerApplication is set, we need to override it. |
| 437 | tag_content SubSystem Console |
| 438 | close_tag Link |
| 439 | ;; |
| 440 | dll) |
| 441 | open_tag Link |
| 442 | tag_content GenerateDebugInformation true |
| 443 | tag_content ModuleDefinitionFile $module_def |
| 444 | close_tag Link |
| 445 | ;; |
| 446 | lib) |
| 447 | ;; |
| 448 | esac |
| 449 | close_tag ItemDefinitionGroup |
| 450 | done |
| 451 | |
| 452 | done |
| 453 | |
| 454 | open_tag ItemGroup |
| 455 | generate_filter "Source Files" "c;cc;cpp;def;odl;idl;hpj;bat;asm;asmx;s" |
| 456 | close_tag ItemGroup |
| 457 | open_tag ItemGroup |
| 458 | generate_filter "Header Files" "h;hm;inl;inc;xsd" |
| 459 | close_tag ItemGroup |
| 460 | open_tag ItemGroup |
| 461 | generate_filter "Build Files" "mk" |
| 462 | close_tag ItemGroup |
| 463 | open_tag ItemGroup |
| 464 | generate_filter "References" "vcxproj" |
| 465 | close_tag ItemGroup |
| 466 | |
| 467 | tag Import \ |
| 468 | Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets" |
| 469 | |
| 470 | open_tag ImportGroup \ |
| 471 | Label="ExtensionTargets" |
| 472 | close_tag ImportGroup |
| 473 | |
| 474 | close_tag Project |
| 475 | |
| 476 | # This must be done from within the {} subshell |
| 477 | echo "Ignored files list (${#file_list[@]} items) is:" >&2 |
| 478 | for f in "${file_list[@]}"; do |
| 479 | echo " $f" >&2 |
| 480 | done |
| 481 | } |
| 482 | |
| 483 | # This regexp doesn't catch most of the strings in the vcxproj format, |
| 484 | # since they're like <tag>path</tag> instead of <tag attr="path" /> |
| 485 | # as previously. It still seems to work ok despite this. |
| 486 | generate_vcxproj | |
| 487 | sed -e '/"/s;\([^ "]\)/;\1\\;g' | |
| 488 | sed -e '/xmlns/s;\\;/;g' > ${outfile} |
| 489 | |
| 490 | exit |