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 13self=$0 14self_basename=${self##*/} 15self_dirname=$(dirname "$0") 16EOL=$'\n' 17 18show_help() { 19 cat <<EOF 20Usage: ${self_basename} --name=projname [options] file1 [file2 ...] 21 22This script generates a Visual Studio project file from a list of source 23code files. 24 25Options: 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) 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 43EOF 44 exit 1 45} 46 47die() { 48 echo "${self_basename}: $@" >&2 49 exit 1 50} 51 52die_unknown(){ 53 echo "Unknown option \"$1\"." >&2 54 echo "See ${self_basename} --help for available options." >&2 55 exit 1 56} 57 58generate_uuid() { 59 local hex="0123456789ABCDEF" 60 local i 61 local uuid="" 62 local j 63 #93995380-89BD-4b04-88EB-625FBE52EBFB 64 for ((i=0; i<32; i++)); do 65 (( j = $RANDOM % 16 )) 66 uuid="${uuid}${hex:$j:1}" 67 done 68 echo "${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}" 69} 70 71indent1=" " 72indent="" 73indent_push() { 74 indent="${indent}${indent1}" 75} 76indent_pop() { 77 indent="${indent%${indent1}}" 78} 79 80tag_attributes() { 81 for opt in "$@"; do 82 optval="${opt#*=}" 83 [ -n "${optval}" ] || 84 die "Missing attribute value in '$opt' while generating $tag tag" 85 echo "${indent}${opt%%=*}=\"${optval}\"" 86 done 87} 88 89open_tag() { 90 local tag=$1 91 shift 92 if [ $# -ne 0 ]; then 93 echo "${indent}<${tag}" 94 indent_push 95 tag_attributes "$@" 96 echo "${indent}>" 97 else 98 echo "${indent}<${tag}>" 99 indent_push 100 fi 101} 102 103close_tag() { 104 local tag=$1 105 indent_pop 106 echo "${indent}</${tag}>" 107} 108 109tag() { 110 local tag=$1 111 shift 112 if [ $# -ne 0 ]; then 113 echo "${indent}<${tag}" 114 indent_push 115 tag_attributes "$@" 116 indent_pop 117 echo "${indent}/>" 118 else 119 echo "${indent}<${tag}/>" 120 fi 121} 122 123tag_content() { 124 local tag=$1 125 local content=$2 126 shift 127 shift 128 if [ $# -ne 0 ]; then 129 echo "${indent}<${tag}" 130 indent_push 131 tag_attributes "$@" 132 echo "${indent}>${content}</${tag}>" 133 indent_pop 134 else 135 echo "${indent}<${tag}>${content}</${tag}>" 136 fi 137} 138 139generate_filter() { 140 local name=$1 141 local pats=$2 142 local file_list_sz 143 local i 144 local f 145 local saveIFS="$IFS" 146 local pack 147 echo "generating filter '$name' from ${#file_list[@]} files" >&2 148 IFS=* 149 150 file_list_sz=${#file_list[@]} 151 for i in ${!file_list[@]}; do 152 f=${file_list[i]} 153 for pat in ${pats//;/$IFS}; do 154 if [ "${f##*.}" == "$pat" ]; then 155 unset file_list[i] 156 157 objf=$(echo ${f%.*}.obj | sed -e 's/^[\./]\+//g' -e 's,/,_,g') 158 159 if ([ "$pat" == "asm" ] || [ "$pat" == "s" ]) && $asm_use_custom_step; then 160 # Avoid object file name collisions, i.e. vpx_config.c and 161 # vpx_config.asm produce the same object file without 162 # this additional suffix. 163 objf=${objf%.obj}_asm.obj 164 open_tag CustomBuild \ 165 Include=".\\$f" 166 for plat in "${platforms[@]}"; do 167 for cfg in Debug Release; do 168 tag_content Message "Assembling %(Filename)%(Extension)" \ 169 Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'" 170 tag_content Command "$(eval echo \$asm_${cfg}_cmdline) -o \$(IntDir)$objf" \ 171 Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'" 172 tag_content Outputs "\$(IntDir)$objf" \ 173 Condition="'\$(Configuration)|\$(Platform)'=='$cfg|$plat'" 174 done 175 done 176 close_tag CustomBuild 177 elif [ "$pat" == "c" ] || \ 178 [ "$pat" == "cc" ] || [ "$pat" == "cpp" ]; then 179 open_tag ClCompile \ 180 Include=".\\$f" 181 # Separate file names with Condition? 182 tag_content ObjectFileName "\$(IntDir)$objf" 183 # Check for AVX and turn it on to avoid warnings. 184 if [[ $f =~ avx.?\.c$ ]]; then 185 tag_content AdditionalOptions "/arch:AVX" 186 fi 187 close_tag ClCompile 188 elif [ "$pat" == "h" ] ; then 189 tag ClInclude \ 190 Include=".\\$f" 191 elif [ "$pat" == "vcxproj" ] ; then 192 open_tag ProjectReference \ 193 Include="$f" 194 depguid=`grep ProjectGuid "$f" | sed 's,.*<.*>\(.*\)</.*>.*,\1,'` 195 tag_content Project "$depguid" 196 tag_content ReferenceOutputAssembly false 197 close_tag ProjectReference 198 else 199 tag None \ 200 Include=".\\$f" 201 fi 202 203 break 204 fi 205 done 206 done 207 208 IFS="$saveIFS" 209} 210 211# Process command line 212unset target 213for opt in "$@"; do 214 optval="${opt#*=}" 215 case "$opt" in 216 --help|-h) show_help 217 ;; 218 --target=*) target="${optval}" 219 ;; 220 --out=*) outfile="$optval" 221 ;; 222 --name=*) name="${optval}" 223 ;; 224 --proj-guid=*) guid="${optval}" 225 ;; 226 --module-def=*) module_def="${optval}" 227 ;; 228 --exe) proj_kind="exe" 229 ;; 230 --dll) proj_kind="dll" 231 ;; 232 --lib) proj_kind="lib" 233 ;; 234 --src-path-bare=*) src_path_bare="$optval" 235 ;; 236 --static-crt) use_static_runtime=true 237 ;; 238 --enable-werror) werror=true 239 ;; 240 --ver=*) 241 vs_ver="$optval" 242 case "$optval" in 243 10|11|12) 244 ;; 245 *) die Unrecognized Visual Studio Version in $opt 246 ;; 247 esac 248 ;; 249 -I*) 250 opt="${opt%/}" 251 incs="${incs}${incs:+;}${opt##-I}" 252 yasmincs="${yasmincs} ${opt}" 253 ;; 254 -D*) defines="${defines}${defines:+;}${opt##-D}" 255 ;; 256 -L*) # fudge . to $(OutDir) 257 if [ "${opt##-L}" == "." ]; then 258 libdirs="${libdirs}${libdirs:+;}\$(OutDir)" 259 else 260 # Also try directories for this platform/configuration 261 libdirs="${libdirs}${libdirs:+;}${opt##-L}" 262 libdirs="${libdirs}${libdirs:+;}${opt##-L}/\$(PlatformName)/\$(Configuration)" 263 libdirs="${libdirs}${libdirs:+;}${opt##-L}/\$(PlatformName)" 264 fi 265 ;; 266 -l*) libs="${libs}${libs:+ }${opt##-l}.lib" 267 ;; 268 -*) die_unknown $opt 269 ;; 270 *) 271 file_list[${#file_list[@]}]="$opt" 272 case "$opt" in 273 *.asm|*.s) uses_asm=true 274 ;; 275 esac 276 ;; 277 esac 278done 279outfile=${outfile:-/dev/stdout} 280guid=${guid:-`generate_uuid`} 281asm_use_custom_step=false 282uses_asm=${uses_asm:-false} 283case "${vs_ver:-11}" in 284 10|11|12) 285 asm_use_custom_step=$uses_asm 286 ;; 287esac 288 289[ -n "$name" ] || die "Project name (--name) must be specified!" 290[ -n "$target" ] || die "Target (--target) must be specified!" 291 292if ${use_static_runtime:-false}; then 293 release_runtime=MultiThreaded 294 debug_runtime=MultiThreadedDebug 295 lib_sfx=mt 296else 297 release_runtime=MultiThreadedDLL 298 debug_runtime=MultiThreadedDebugDLL 299 lib_sfx=md 300fi 301 302# Calculate debug lib names: If a lib ends in ${lib_sfx}.lib, then rename 303# it to ${lib_sfx}d.lib. This precludes linking to release libs from a 304# debug exe, so this may need to be refactored later. 305for lib in ${libs}; do 306 if [ "$lib" != "${lib%${lib_sfx}.lib}" ]; then 307 lib=${lib%.lib}d.lib 308 fi 309 debug_libs="${debug_libs}${debug_libs:+ }${lib}" 310done 311debug_libs=${debug_libs// /;} 312libs=${libs// /;} 313 314 315# List of all platforms supported for this target 316case "$target" in 317 x86_64*) 318 platforms[0]="x64" 319 asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} "%(FullPath)"" 320 asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} "%(FullPath)"" 321 ;; 322 x86*) 323 platforms[0]="Win32" 324 asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} "%(FullPath)"" 325 asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} "%(FullPath)"" 326 ;; 327 arm*) 328 asm_Debug_cmdline="armasm -nologo "%(FullPath)"" 329 asm_Release_cmdline="armasm -nologo "%(FullPath)"" 330 if [ "$name" = "obj_int_extract" ]; then 331 # We don't want to build this tool for the target architecture, 332 # but for an architecture we can run locally during the build. 333 platforms[0]="Win32" 334 else 335 platforms[0]="ARM" 336 fi 337 ;; 338 *) die "Unsupported target $target!" 339 ;; 340esac 341 342generate_vcxproj() { 343 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" 344 open_tag Project \ 345 DefaultTargets="Build" \ 346 ToolsVersion="4.0" \ 347 xmlns="http://schemas.microsoft.com/developer/msbuild/2003" \ 348 349 open_tag ItemGroup \ 350 Label="ProjectConfigurations" 351 for plat in "${platforms[@]}"; do 352 for config in Debug Release; do 353 open_tag ProjectConfiguration \ 354 Include="$config|$plat" 355 tag_content Configuration $config 356 tag_content Platform $plat 357 close_tag ProjectConfiguration 358 done 359 done 360 close_tag ItemGroup 361 362 open_tag PropertyGroup \ 363 Label="Globals" 364 tag_content ProjectGuid "{${guid}}" 365 tag_content RootNamespace ${name} 366 tag_content Keyword ManagedCProj 367 close_tag PropertyGroup 368 369 tag Import \ 370 Project="\$(VCTargetsPath)\\Microsoft.Cpp.Default.props" 371 372 for plat in "${platforms[@]}"; do 373 for config in Release Debug; do 374 open_tag PropertyGroup \ 375 Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'" \ 376 Label="Configuration" 377 if [ "$proj_kind" = "exe" ]; then 378 tag_content ConfigurationType Application 379 elif [ "$proj_kind" = "dll" ]; then 380 tag_content ConfigurationType DynamicLibrary 381 else 382 tag_content ConfigurationType StaticLibrary 383 fi 384 if [ "$vs_ver" = "11" ]; then 385 if [ "$plat" = "ARM" ]; then 386 # Setting the wp80 toolchain automatically sets the 387 # WINAPI_FAMILY define, which is required for building 388 # code for arm with the windows headers. Alternatively, 389 # one could add AppContainerApplication=true in the Globals 390 # section and add PrecompiledHeader=NotUsing and 391 # CompileAsWinRT=false in ClCompile and SubSystem=Console 392 # in Link. 393 tag_content PlatformToolset v110_wp80 394 else 395 tag_content PlatformToolset v110 396 fi 397 fi 398 if [ "$vs_ver" = "12" ]; then 399 if [ "$plat" = "ARM" ]; then 400 # Setting the wp80 toolchain automatically sets the 401 # WINAPI_FAMILY define, which is required for building 402 # code for arm with the windows headers. Alternatively, 403 # one could add AppContainerApplication=true in the Globals 404 # section and add PrecompiledHeader=NotUsing and 405 # CompileAsWinRT=false in ClCompile and SubSystem=Console 406 # in Link. 407 tag_content PlatformToolset v120_wp80 408 else 409 tag_content PlatformToolset v120 410 fi 411 fi 412 tag_content CharacterSet Unicode 413 if [ "$config" = "Release" ]; then 414 tag_content WholeProgramOptimization true 415 fi 416 close_tag PropertyGroup 417 done 418 done 419 420 tag Import \ 421 Project="\$(VCTargetsPath)\\Microsoft.Cpp.props" 422 423 open_tag ImportGroup \ 424 Label="PropertySheets" 425 tag Import \ 426 Project="\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props" \ 427 Condition="exists('\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props')" \ 428 Label="LocalAppDataPlatform" 429 close_tag ImportGroup 430 431 tag PropertyGroup \ 432 Label="UserMacros" 433 434 for plat in "${platforms[@]}"; do 435 plat_no_ws=`echo $plat | sed 's/[^A-Za-z0-9_]/_/g'` 436 for config in Debug Release; do 437 open_tag PropertyGroup \ 438 Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'" 439 tag_content OutDir "\$(SolutionDir)$plat_no_ws\\\$(Configuration)\\" 440 tag_content IntDir "$plat_no_ws\\\$(Configuration)\\${name}\\" 441 if [ "$proj_kind" == "lib" ]; then 442 if [ "$config" == "Debug" ]; then 443 config_suffix=d 444 else 445 config_suffix="" 446 fi 447 tag_content TargetName "${name}${lib_sfx}${config_suffix}" 448 fi 449 close_tag PropertyGroup 450 done 451 done 452 453 for plat in "${platforms[@]}"; do 454 for config in Debug Release; do 455 open_tag ItemDefinitionGroup \ 456 Condition="'\$(Configuration)|\$(Platform)'=='$config|$plat'" 457 if [ "$name" == "vpx" ]; then 458 hostplat=$plat 459 if [ "$hostplat" == "ARM" ]; then 460 hostplat=Win32 461 fi 462 open_tag PreBuildEvent 463 tag_content Command "call obj_int_extract.bat $src_path_bare $hostplat\\\$(Configuration)" 464 close_tag PreBuildEvent 465 fi 466 open_tag ClCompile 467 if [ "$config" = "Debug" ]; then 468 opt=Disabled 469 runtime=$debug_runtime 470 curlibs=$debug_libs 471 case "$name" in 472 obj_int_extract) 473 debug=DEBUG 474 ;; 475 *) 476 debug=_DEBUG 477 ;; 478 esac 479 else 480 opt=MaxSpeed 481 runtime=$release_runtime 482 curlibs=$libs 483 tag_content FavorSizeOrSpeed Speed 484 debug=NDEBUG 485 fi 486 case "$name" in 487 obj_int_extract) 488 extradefines=";_CONSOLE" 489 ;; 490 *) 491 extradefines=";$defines" 492 ;; 493 esac 494 tag_content Optimization $opt 495 tag_content AdditionalIncludeDirectories "$incs;%(AdditionalIncludeDirectories)" 496 tag_content PreprocessorDefinitions "WIN32;$debug;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE$extradefines;%(PreprocessorDefinitions)" 497 tag_content RuntimeLibrary $runtime 498 tag_content WarningLevel Level3 499 if ${werror:-false}; then 500 tag_content TreatWarningAsError true 501 fi 502 close_tag ClCompile 503 case "$proj_kind" in 504 exe) 505 open_tag Link 506 if [ "$name" != "obj_int_extract" ]; then 507 tag_content AdditionalDependencies "$curlibs" 508 tag_content AdditionalLibraryDirectories "$libdirs;%(AdditionalLibraryDirectories)" 509 fi 510 tag_content GenerateDebugInformation true 511 close_tag Link 512 ;; 513 dll) 514 open_tag Link 515 tag_content GenerateDebugInformation true 516 tag_content ModuleDefinitionFile $module_def 517 close_tag Link 518 ;; 519 lib) 520 ;; 521 esac 522 close_tag ItemDefinitionGroup 523 done 524 525 done 526 527 open_tag ItemGroup 528 generate_filter "Source Files" "c;cc;cpp;def;odl;idl;hpj;bat;asm;asmx;s" 529 close_tag ItemGroup 530 open_tag ItemGroup 531 generate_filter "Header Files" "h;hm;inl;inc;xsd" 532 close_tag ItemGroup 533 open_tag ItemGroup 534 generate_filter "Build Files" "mk" 535 close_tag ItemGroup 536 open_tag ItemGroup 537 generate_filter "References" "vcxproj" 538 close_tag ItemGroup 539 540 tag Import \ 541 Project="\$(VCTargetsPath)\\Microsoft.Cpp.targets" 542 543 open_tag ImportGroup \ 544 Label="ExtensionTargets" 545 close_tag ImportGroup 546 547 close_tag Project 548 549 # This must be done from within the {} subshell 550 echo "Ignored files list (${#file_list[@]} items) is:" >&2 551 for f in "${file_list[@]}"; do 552 echo " $f" >&2 553 done 554} 555 556# This regexp doesn't catch most of the strings in the vcxproj format, 557# since they're like <tag>path</tag> instead of <tag attr="path" /> 558# as previously. It still seems to work ok despite this. 559generate_vcxproj | 560 sed -e '/"/s;\([^ "]\)/;\1\\;g' | 561 sed -e '/xmlns/s;\\;/;g' > ${outfile} 562 563exit 564