#!/usr/bin/perl # Copyright (c) 2021 Samsung Electronics Co., 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. use Config; use Cwd; use Cwd 'abs_path'; use File::Basename; use File::Path; use File::Copy; use File::Copy::Recursive qw(dircopy); use strict; use Getopt::Long; use Pod::Usage; ################################################################################ # SYSTEM PACKAGES # ################################################################################ # Add any required system packages to this list - if they are not present, then # this script will attempt to install them for you. my @system_packages = ( "automake", "cmake", "g++", "pkg-config", "libtool", "ccache", "libexif-dev", "libgles2-mesa-dev", "libdrm-dev", "libgif-dev", "libturbojpeg", "libturbojpeg0-dev", "libfribidi-dev", "libharfbuzz-dev", "libhyphen-dev", "doxygen", "lcov", "libcurl4-gnutls-dev", "curl", "libssl-dev", "cifs-utils", "libgtest-dev", "libcairo2-dev", "libopencv-dev", "gettext", "libwebp-dev", ); my $ubuntu_version = (split(/\s+/, `lsb_release -d`))[2]; if (${ubuntu_version} > 20) { # Add unique packages for 20.04 and above push @system_packages, "libefl-all-dev"; } else { # Add unique packages for Ubuntu releases before 20.04 push @system_packages, "libelementary-dev"; } # Some packages like require building from source # v8 is currently disabled until we can get it working without a http proxy being setup my @source_pkgs = ( {"name" => "disabled-v8", "force-rebuild" => 0, "use_depot_tools" => 1, "repo" => "https://chromium.googlesource.com/v8/v8.git", "depot_tools_repo" => "https://chromium.googlesource.com/chromium/tools/depot_tools.git", # original version used with DALi is 3.25.19. 3.32.7 is the latest we can use before # upgrading DALi to use c++0x or c++11 "version" => " 3.32.7", "make" => "make -j8 library=shared", "build-mode" =>"debug" }, {"name" => "gtest" }, ); ### Detect any http proxy, part of v8 installation requires this information my $http_proxy_port; my $http_proxy_ip; if( exists $ENV{http_proxy} ) { # string split into 3 items http, //ip, port my @http_proxy_info = split( /:/,$ENV{http_proxy}, ); $http_proxy_ip = @http_proxy_info[1]; $http_proxy_ip =~ s/[\/]//g;; # remove forward slashes $http_proxy_port = @http_proxy_info[2]; } # Make best guess as to where this program was run from (note, it is # always possible to override the location of $0 by the calling # program, so we can't really tell for sure that this is where we # expect it to be. :/ my $new_env = 0; my $exec_path = $0; if($0 !~ m!^/!) { $exec_path = abs_path($0); } $exec_path = dirname($exec_path); my $root_path = getcwd(); # Search for the root dali-env directory if($exec_path =~ m!dali-env/opt/bin!) { # We are using the installed dali_env script $root_path = $exec_path; while(basename($root_path) ne "dali-env" && $root_path ne "") { $root_path = dirname($root_path); } } elsif($root_path =~ m!dali-env$! or $root_path =~ m!dali-env/!) { # We are NOT using the installed dali_env script # Find dali-env root from current directory while(basename($root_path) ne "dali-env" && $root_path ne "") { $root_path = dirname($root_path); } } else { # dali-env root dir should be in the current directory $root_path .= "/dali-env"; if(! -e $root_path) { # Creating a new dali-env $new_env = 1; } } my $src_path = "$root_path/src-packages"; my $sbs_path = "$root_path/target"; my $install_path = "$root_path/opt"; my $opt_create=0; my $opt_setenv=0; my $opt_help=0; my $opt_man=0; GetOptions("create" => \$opt_create, "setenv" => \$opt_setenv, "help" => \$opt_help, "man" => \$opt_man) or pod2usage(2); pod2usage(1) if $opt_help; pod2usage(-exitstatus => 0, -verbose => 2) if $opt_man; ################################################################################ sub create_env { mkpath("$install_path/bin"); mkpath("$install_path/lib/pkgconfig"); mkpath("$install_path/include"); mkpath("$install_path/share/aclocal"); mkpath("$src_path"); mkpath("$sbs_path"); copy($0, "$install_path/bin/dali_env"); chmod(0755, "$install_path/bin/dali_env"); } ################################################################################ sub in_dali_env { my $cwd = substr(getcwd(), 0, length($root_path)); #print "cwd = $cwd\nroot = $root_path\n"; return $cwd eq $root_path; } ################################################################################ sub create_setenv { print <<"EOF"; # # To use the desktop libraries, please add the following lines to your .bashrc or # create a setenv script from them, e.g. by running this command as follows # \$ $install_path/bin/dali_env -s > setenv # # You can then source this script by using # \$ . setenv # # Use DESKTOP_PREFIX when running configure or cmake in dali/build/tizen: # \$ CXXFLAGS="-g -O0" ./configure --prefix=\$DESKTOP_PREFIX # _OR_ # \$ CXXFLAGS="-g -O0" cmake -DCMAKE_INSTALL_PREFIX=\$DESKTOP_PREFIX export DESKTOP_PREFIX=$install_path export PATH=$install_path/bin:\$PATH export LD_LIBRARY_PATH=$install_path/lib:\$LD_LIBRARY_PATH export INCLUDEDIR=$install_path/include export PKG_CONFIG_PATH=$install_path/lib/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig export DOTNET_CLI_TELEMETRY_OPTOUT=1 export DALI_WINDOW_WIDTH=480 export DALI_WINDOW_HEIGHT=800 EOF } ################################################################################ sub check_system_package { my $package; foreach $package (@_) { my @x=split(/\s+/, `dpkg -l $package 2> /dev/null|grep $package`); if($x[0] ne "ii") { # Check if the package is available to install, exit-code is 0 if the package is found. if(system("apt-cache show $package > /dev/null 2>&1") == 0) { print "Attempting to install $package\n"; system("sudo apt-get -y --force-yes install $package"); } } } } sub check_system_packages { print "Checking for required system packages (may require sudo password)\n"; check_system_package(@system_packages); my $gnome_v =`dpkg -l gnome-common| tail -1| sed "s/ \\+/ /g" | cut -d' ' -f 3`; my @am = split(/\./, `automake --version | head -1 | cut -f4 -d' '`); if($gnome_v =~ /$2.24/ && $am[1]>10) { die "Gnome common and automake are not compatible - automake is too new\n"; } my @gpp_v = (`g++ --version | head -1` =~ /(\d+)\.(\d+)\.(\d+)/); if(! (($gpp_v[0] > 4) || ($gpp_v[0] == 4 && $gpp_v[1] > 4) || ($gpp_v[0] == 4 && $gpp_v[1] == 4 && $gpp_v[2] >= 5))) { die "You need g++ 4.5.1 or greater to build dali\n"; } } sub check_source_packages { my $pkgref; foreach $pkgref (@source_pkgs) { my $pkg = $pkgref->{"name"}; if($pkg eq "v8") { install_v8( $pkgref ); } elsif ($pkg eq "gtest") { if(! -e "/usr/lib/libgtest.a") { print "Attempting to build $pkg\n"; # from https://www.eriksmistad.no/getting-started-with-google-test-on-ubuntu/ run_command("cd /usr/src/gtest; sudo cmake CMakeLists.txt; sudo make; sudo cp *.a /usr/lib; cd -;"); } } } } ################################################################################ sub create_link { my $arch=`uname -i`; $arch =~ s/\r|\n//g; my $link = "/usr/lib/$arch-linux-gnu/libturbojpeg.so"; unless (-e $link) { print "Creating libjpegturbo symbolic link\n"; system("sudo ln -s $link.0 $link"); } } ################################################################################ # Helper to run and print out the command being run and quit if it fails # sub run_command { my $command = $_[0]; my $ret; print("Running: $command\n"); $ret = system("$command"); if($ret >> 8) { die "$command failed \n"; } } ################################################################################ # later versions of v8 (post mid 2014) require googles depot_tools to build. # sub install_google_depot_tools { #### # clone the depo_tools into the source directory and set the path up #### my $v8 = $_[0]; my $depot_tools_directory = $src_path . "/depot_tools"; my $depot_tools_repo = $v8->{"depot_tools_repo"}; # clear the directory if exists rmtree( $depot_tools_directory ); # clone the depot tools run_command( "git clone " . $depot_tools_repo. " " . $depot_tools_directory ); # add it the the path $ENV{PATH} = "$ENV{PATH}:$depot_tools_directory"; # need to setup a config file for the proxy create_boto_config_file( $v8 , $depot_tools_directory ); # set the config location as an environment variable ( used by scripts depot_tools) $ENV{NO_AUTH_BOTO_CONFIG}="$src_path/depot_tools/.boto"; # change to depot tools directory chdir( $depot_tools_directory ); # fetch v8 run_command("fetch --nohooks v8"); } ################################################################################ # later versions of v8 use boto, which currently requires having proxy manually set # sub create_boto_config_file { my $v8 = $_[0]; my $depot_tools_directory = $_[1]; print(" depot_tools directory = $depot_tools_directory\n"); print("Configuring boto with http proxy IP = ". $http_proxy_ip . ", Port = " . $http_proxy_port . "\n"); # Create the proxy info for the boto file my $fileContents = <<"END"; [Boto] debug = 0 num_retries = 2 proxy = $http_proxy_ip proxy_port = $http_proxy_port END # Place the config file in the depot tools folder my $filename = $depot_tools_directory . "/" . ".boto"; print("Creating Boto config file with proxy settings to file ". $filename . "\n"); my $fh; open( $fh, '>', $filename ); print { $fh } $fileContents; close( $fh ); # export the environment variable run_command("gclient config https://gclient.googlecode.com/svn/trunk/gclient"); run_command("gclient runhooks"); } ################################################################################ # We need a specific version of V8 to work with DALi # - Check a txt file in dali-env to see if v8 needs upgrading (checks gcc version too) # - Clones the source # - builds dependencies (v8 automatically clones it's GYP build system) # - Builds it # - Create a package file # It is cloned, then built from source, we create a package file for it, then # it's copied into dali-env sub install_v8 { my $v8 = $_[0]; my $ret; my $v8Version = $v8->{"version"}; print( "Checking if V8 ". $v8Version. " is installed \n"); #### # Check currently installed version # We create a text file with v8 and gcc version in the filename to compare with # Version file is stored as "v8_2.3.4_installed_built_with_gcc_4_8_3.txt" #### # get the gcc version, so if the compiler is updated v8 is re-built # note: v8 requires gcc version GCC >= 4.6 my $gccVersion = `gcc --version | grep ^gcc | sed 's/^.* //g'`; chomp( $gccVersion ); my $versionTextFile = $src_path . "/v8_" . $v8Version. "_" . $v8->{"build-mode"} . "_installed_built_with_gcc_". $gccVersion .".txt"; # use stat to see if file exists my @install_stats = stat $versionTextFile; if( (scalar(@install_stats)) && $v8->{"force-rebuild"} != 1 ) { print("Correct V8 version installed\n"); return; } else { # delete older versions of the version file first ( otherwise when downgrading it thinks version is still installed) system( "rm " . $src_path . "/v8_*.txt >/dev/null 2>&1"); } #### # Clone the v8 source repository and checkout the version we want #### # Need to clone it from repo my $v8_source_directory; # newer version of v8 use depot_tools with gclient, git cloned builds do not work if( $v8->{"use_depot_tools"} == 1) { install_google_depot_tools( $v8 ); # v8 is checkout out under depot_tools path $v8_source_directory = $src_path . "/depot_tools/v8"; } else { $v8_source_directory = $src_path . "/v8"; # delete the old v8 source directpry if exists rmtree( $v8_source_directory ); # clone the repository run_command( "git clone " . $v8->{"repo"} . " " . $v8_source_directory ); } # change to the source directoy for the checkout chdir( $v8_source_directory ); # checkout the version DALi is compatible with run_command( "git checkout ". $v8Version ); #### # Run make dependencies then make for the specific target #### if( $v8->{"use_depot_tools"} == 1) { run_command("gclient sync"); } else { run_command("make dependencies"); } # assemble the make command my $makeCommand = $v8->{"make"}; # need to append architecture and build mode, e.g. x64.debug my $buildTarget; if( $Config{use64bitint} ) { print("Building 64 bit version of V8\n"); $buildTarget= "x64." . $v8->{"build-mode"} } else{ print("Building 32 bit version of V8\n"); $buildTarget= "ia32." . $v8->{"build-mode"} } $makeCommand .= " " . $buildTarget; print("Running: $makeCommand\n"); run_command( $makeCommand ); #### # Manually install the library / header files #### # Need to manually install (make install not available on v8 ) my $libSourceDir = "$v8_source_directory/out/$buildTarget/lib.target/"; my $headerSourceDir = "$v8_source_directory/include/"; my $libDestinationDir = $install_path . "/lib/"; my $headerDestinationDir = $install_path . "/include/v8/"; # delete any current v8 libs system( "rm " . $libDestinationDir . "libv8*"); system( "rm " . $libDestinationDir . "libicu*"); # copy the library and header files dircopy( $libSourceDir, $libDestinationDir); dircopy( $headerSourceDir, $headerDestinationDir); # Copy libv8.so to libv8.so.version ( e.g. libv8.so.1.2.4) my $v8SoFile = $libDestinationDir . "libv8.so"; my $v8SoVersionFile = $libDestinationDir . "libv8.so." . $v8Version; move( $v8SoFile, $v8SoVersionFile ); # symlink the libv8.so.1.2.3 to libv8.so symlink( $v8SoVersionFile, $v8SoFile ); print( "source dir = " . $libSourceDir . " dest dir ". $libDestinationDir . " \n" ); #### # Create the package file in, # we keep the library files and header files in v8 sub-directories #### my $fileContents = <<"END"; prefix=$install_path exec_prefix=\${prefix} apiversion=$v8Version libdir=\${exec_prefix}/lib includedir=\${prefix}/include/v8 Name: v8 JavaScript engine - runtime library Description: V8 is Google's open source JavaScript engine. Version: \${apiversion} Libs: -L\${libdir} -lv8 -licuuc -licui18n Cflags: -I\${includedir} END my $filename = $install_path . "/lib/pkgconfig/" . "v8.pc"; print("writing to file ". $filename . "\n"); my $fh; if( open( $fh, '>', $filename ) ) { print { $fh } $fileContents; close( $fh ); } else { die "failed to create " . $filename ."\n"; } print("Installed V8 " .$v8Version . " OK\n"); ##### # #### my $versionFile; open( $versionFile, '>', $versionTextFile ); close( $versionFile ); print("Installing V8 version $v8Version\n"); } ################################################################################ # MAIN ################################################################################ if($opt_create) { my $new_root = getcwd() . "/dali-env"; if($exec_path =~ m!dali-env/opt/bin!) { die "Already in a dali-env directory\n"; # Could query if user wants to re-create? } elsif(-e $root_path) { die "$root_path already exists\n"; } elsif(-e $new_root) { die "A dali-env directory already exists here\n"; } check_system_packages(); create_link(); create_env(); # do this after source directory structure created in create_env check_source_packages(); create_setenv(); } elsif($opt_setenv) { if(! -d $root_path) { die "$root_path does not exist\n"; } elsif($new_env) { die "$root_path is not an existing environment\n"; } create_setenv(); } else { pod2usage(1); } __END__ =head1 NAME dali_env - Create the DALi environment for Ubuntu =head1 SYNOPSIS dali_env [-c] [-s] [-h|-m] =head1 OPTIONS =over 28 =item B<-c|--create> Create a DALi environment directory in the current directory. =item B<-s|--setenv> Display environment variables to setup. =item B<-h|--help> Display this help =item B<-m|--man> Display the manual page =back =head1 DESCRIPTION B Gets the required dependencies for DALi and them to a local directory. Can also create a setenv script to point to the installation. =cut