Xedi.Xermawan's Blog

personal-technical blog

Archive for the ‘Scripting&Automation’ Category

Mencoba Cmake ( a Cmake intro )

leave a comment »

Visual Studio adalah favorite ide pemrograman saya. Sudah sejak lama saya pakai, kira-kira sejak 4 tahun yang lalu. Mungkin menjadi favorite karena kebiasaan ūüôā dan juga visual studio mudah dipakai. Walaupun kadang ada juga bugs ‘aneh’ yang terjadi selama nge-build project dengan VS. Sayangnya, ‘build file’ dari VS tidak bisa dipakai di environment lain, misalnya mau build pakai gcc di Linux. Oleh karena itulah harus ada cara lain yang harus dipakai. Berikut sebagai contoh case saya :

Misalnya saya memiliki super advanced top secret project dengan informasi sebagai berikut :

[1] struktur file-file project :

              ->project_root_dir

              ->HelloSource.cpp file

              ->PrintLib dir

                      ->PrintHello.h file

             ->PrintHello.cpp file

[2] project diatas akan di-build dengan output sebagai berikut :

¬† ¬† ¬† ¬† ¬† ¬†-HelloSource.cpp —> executable file , yang menggunakan PrintLib (static linked)

¬† ¬† ¬† ¬† ¬† ¬†-PrintLib —> static library

          -Penggunaan PrintLib bisa di ON-OFF melalui macro ( o yeah, macro define, I like it )

[3] source code : HelloSource.cpp

          /* hello apps project */

          #include <iostream>

¬† ¬† ¬† ¬† ¬† #include “HelloVersion.h”

          #ifdef USE_PRINTLIB

¬† ¬† ¬† ¬† ¬† #include “PrintHello.h”

          #endif

          using namespace std;

          int main(char* argc, char** argv)

          {

¬† ¬† ¬† ¬† ¬†¬† ¬† ¬† ¬† ¬† cout << “hello ” << endl;

¬† ¬† ¬† ¬† ¬†¬† ¬† ¬† ¬† ¬† cout <<” hello version : “<< Hello_VERSION_MAJOR <<“-“<<Hello_VERSION_MINOR<<endl;

                   #ifdef USE_PRINTLIB

                   PrintHelloFunc();

                   #endif

                   return 0;

          }

[4] source code : PrintHello.h

          #include <iostream>

          void PrintHelloFunc();

[5] source code : PrintHello.cpp

¬† ¬† ¬† ¬† ¬† #include “PrintHello.h”

          void PrintHelloFunc()

          {

¬† ¬† ¬† ¬† ¬†¬† ¬† ¬† ¬† ¬† std::cout << ” hey hello i’m here. printed from hellolib ” << std::endl;

          }

Pertanyaannya, Bagaimana agar project diatas bisa build-able beberapa platform dengan beda compiler ?

Banyak cara, dari cara manual ( buat build script untuk masing-masing platform ) atau dengan tools misalnya : autotools, scons, jam, waf, cmake.yang terakhir: cmake, saya sering mem-build project dari internet yang menggunakan cmake, jadi lebih kenal dengan yang satu ini. Kenyataannya cmake sudah secara luas digunakan di opensource project sejak lama. Build sistem yang lain yang pernah saya coba, dan sangat mudah (dari segi user yang akan mem-build project tersebut) adalah build sistem dari boost library : boost-jam . sangat mudah nge-buildnya.

Kali ini saya tertarik mempelajari bagaimana membuat cmake file. cmake file itu semacam “template” make file atau meta make file. cmake file adalah file text yang berisi deskripsi project dengan syntax cmake dan disimpan dengan nama CMakeLists.txt. Kalau cmake file suatu project sudah dibuat, file ini bisa digunakan untuk meng-generate real make file yang bisa dipakai compiler. tergantung compiler apa yang dipakai . beberapa yang didukung :

          -Visual C++ ( sln & vcxproj ),

          -Kdevelop3, Eclipse, XCode,

          -makefiles (Unix,NMake, Borland, Watcom, MinGW, MSYS,Cygwin)

          -Code::Blocks

Dari daftar diatas, yang pernah saya coba adalah generate VS (solution & project) dan makefile untuk linux.

Dari deskripsi project diatas saya bisa membuat cmake file dengan struktur :

          ->project_root_dir

          ->CMakeLists.txt file                   cmake ke-1 (main)

          ->PrintLib dir

                   ->CMakeLists.txt file          cmake ke-2

          ->HelloVersion.h.in file untuk setting Define

 source file CMakeLists.txt ke-2 : ( hanya 1 baris )

          add_library(PrintLib PrintHello.cpp)

source file CMakeLists.txt ke-1 :

          #this is a cmake comment

          cmake_minimum_required (VERSION 2.6)

          #project name

          project (Hello)

          #version

          set (Hello_VERSION_MAJOR 1)

          set (Hello_VERSION_MINOR 0)

          #option can be turned on/off when generate real make file

¬† ¬† ¬† ¬† ¬† option ( USE_PRINTLIB “use print library” ON )

          configure_file (

¬† ¬† ¬† ¬† ¬†¬† ¬† ¬† ¬† ¬† “${PROJECT_SOURCE_DIR}/HelloVersion.h.in”

¬† ¬† ¬† ¬† ¬†¬† ¬† ¬† ¬† ¬† “${PROJECT_BINARY_DIR}/HelloVersion.h”

          )

¬† ¬† ¬† ¬† ¬† include_directories (“${PROJECT_BINARY_DIR}”)

          if (USE_PRINTLIB)

¬† ¬† ¬† ¬† ¬†¬† ¬† ¬† ¬† ¬† include_directories (“${PROJECT_SOURCE_DIR}/PrintLib”)

                   add_subdirectory(PrintLib)

                   set (EXTRA_LIBS ${EXTRA_LIBS} PrintLib)

          endif (USE_PRINTLIB)

          #tell cmake that Hello is executable

          add_executable(Hello HelloSource.cpp)

          #tell cmake that Hello linked with extralibs ( printlib )

          target_link_libraries(Hello ${EXTRA_LIBS})

          install(TARGETS Hello DESTINATION bin)

source file HelloVersion.h.in :

          // version for Hello project

          #define Hello_VERSION_MAJOR @Hello_VERSION_MAJOR@

          #define Hello_VERSION_MINOR @Hello_VERSION_MINOR@

          #cmakedefine USE_PRINTLIB

file tambahan adalah HelloVersion.h.in untuk mengatur version dan macro define. Kalau dibaca deskripsi output project saya diatas dan apa yang ada di cmakelist.txt semuanya tampak self explanatory. Dari CMakeLists.txt ini kita bisa meng-generate solution & project di windows & makefile di linux ( sebagai 2 test case untuk mencoba ) . di Ms-Windows bisa memakai cmake GUI.

cmake_flow

cmake_flow

Cmake file yang dipakai diatas adalah yang paling sederhana. Terdapat beberapa perintah yang lain, misalnya find_package, find_library, export, dan lainnya .

edie // 13022015 // Jakarta

Written by XediXermawan

February 13, 2015 at 4:30 pm

Auto beautifying C++ code

leave a comment »

Disini saya ingin share simple script untuk “mempercantik” c++ code disuatu folder project dan melakukan svn commit setelah itu. jadi semacam selalu ada auto corrector jika kamu menulis code yang tidak sesuai aturan ( bahkan mungkin aturan yang kamu buat sendiri) .

code yang rapih diharapkan memiliki sedikit bugs dan juga ingat programmer menulis code tidak hanya untuk mesin, tetapi juga untuk dibaca manusia yang lain. untung nya untuk masalah indentation & formating ada software keren & free untuk melakukan ini, yaitu AStyle (  http://astyle.sourceforge.net/ )  .  dengan batch script dibawah ini, semuanya terjadi otomatis :


@echo off
SET ASTYLE_DIR="N:\test\AStyle\bin"
SET SRC_ROOT_DIR="N:\test\test_astyle\source01"
echo ..AStyle beautfying...
%ASTYLE_DIR%\AStyle.exe --style=google --indent=spaces=4 -xn -xc -xl -xk -xe -n --align-pointer=type --recursive %SRC_ROOT_DIR%\*.h %SRC_ROOT_DIR%\*.cpp %SRC_ROOT_DIR%\*.hpp %SRC_ROOT_DIR%\*.c
echo ..done..
echo ..SVN Comitting..
svn commit %SRC_ROOT_DIR% --message "auto commit: Astyle auto beautify code "
echo ..done..

SET ASTYLE_DIR         : dir dari astyle exe

SET SRC_ROOT_DIR  : root dir source code

dengan menambahkan ini scheduler task / script semuanya berjalan otomatis .

// edie  // surabaya 23-12-2013

Written by XediXermawan

December 23, 2013 at 9:40 am

File mana yang termodifikasi ?

leave a comment »

Misalnya saya memiliki 1000 file yang akan saya prosess oleh suatu program, dengan script saya bisa melakukannya seperti ini :

for i=0 to i=1000 { process file ke-i }      

jadi dengan klik sebuat script pekerjaan selesai. Namun, ada beberapa file dari 1000 file tersebut yang berubah / saya modifikasi lagi, sehingga saya perlu mengulang eksekusi script diatas lagi :

for i=0 to i=1000 { process file ke-i }      

Ini tentu tidak efisien dan lama, karena saya mengubah beberapa file, namun 1000 file masih diprocess lagi. Kode yang efisien seharusnya begini :

for i=0 to i=1000 { jika file ke-i ter-modifikasi, maka process file ke-i }    

untuk itu saya perlu suatu program untuk mengecek apakah file ke-i, termodifikasi / tidak. Pekerjaan semacam ini bisa mungkin saja dilakukan dengan python, lua, atau scripting language yang lain. Namun kali ini , (dan waktu2yg lain) , saya suka pakai c/c++ dengan kombinasi Batch , hehehe. Dan, program super simple itu sudah jadi, xediff.exe :d . berikut contoh efisien script yang saya maksud .

[ run_works.bat ]

@echo off
SET XDIFF=N:\XediProjects\Release\Xediff.exe
SET TARGETDIR=D:\test\test
for %%i in ( %TARGETDIR%\*.* ) do (
 call checkmodified.bat %%i
)
echo .. Done..

[ checkmodified.bat ]

@echo off
%XDIFF% %1 > temp.txt
set /p XDF= < temp.txt
 if "%XDF%"=="1" (
 @echo ..do something: this file changed %1 %XDF%
 )
del temp.txt

Terdapat 2 file batch,¬†run_works.bat yang memanggil¬†checkmodified.bat. Alasan kenapa jadi 2 file BAT adalah : pipe di BAT tidak bisa bekerja. { apa itu pipe? } . lalu apa yang dilakukan xediff.exe? : xediff.exe menerima argumen berupa file path , dan memberikan output (stdout) ‘1’ & ‘0’ ¬†,file termodifikasi atau tidak . xediff.exe adalah program simple yang mengecek last written time dari suatu file . berikut kodenya [ this is ugly, but i like to share ūüôā ¬† ¬†]

[xediff.exe]

// Xedi Xermawan <c> 2013
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <fstream>

using namespace std;

bool GetLastWriteTime(HANDLE hFile, SYSTEMTIME& lastaccess,TCHAR* fileLastAccess)	{
	bool isEqual = true;
    FILETIME ftCreate, ftAccess, ftWrite;
    SYSTEMTIME stUTC, stLocal;
    // Retrieve the file times for the file.
    if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
        return false;
    // Convert the last-write time to local time.
    FileTimeToSystemTime(&ftWrite, &stUTC);
    SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
	if(stLocal.wMonth != lastaccess.wMonth ||
	   stLocal.wDay!= lastaccess.wDay ||
	   stLocal.wYear!= lastaccess.wYear ||
       stLocal.wHour!= lastaccess.wHour ||
	   stLocal.wMinute!= lastaccess.wMinute ||
	   stLocal.wSecond!= lastaccess.wSecond
	   )
	{
		isEqual = false;
	}
	fstream fileOut(fileLastAccess,std::ios::out|std::ios::binary);
	const char* c=reinterpret_cast<const char*>(&stLocal);
	fileOut.write(c,sizeof(stLocal));
	fileOut.close();
	return isEqual;
}

bool GetLastTimeAccess(SYSTEMTIME& ret, TCHAR* fileLastAccess)  {
	fstream fileIn(fileLastAccess,std::ios::in | std::ios::binary);
	if(!fileIn) {
		return false;
	}
	fileIn.read( reinterpret_cast<char*>(&ret), sizeof(ret) );
	fileIn.close();
	return true;
}

void BreakPath(TCHAR* filepath, TCHAR* filedir, TCHAR* filename)	{
	unsigned int i=0,lastSlash=0;
	TCHAR buff[MAX_PATH];
	while(*filepath !='')	{
		buff[i] = *filepath;
		if(*filepath++=='\\')
			lastSlash=i;
		i++;
	}
	buff[i]='\0';
	i=0;
	while(i < lastSlash+1)	{
		*filedir++ = buff[i++];
	}
	*filedir++ ='.';
	*filedir++ ='x';
	*filedir++ ='d';
	*filedir++ ='f';
	*filedir++ ='\\';
	*filedir='';
	while(buff[i] !='')	{
		*filename++ = buff[i++];
	}
	*filename ='\0';
}

void FixPath(TCHAR* filedir, TCHAR* filename,TCHAR* filenamefix)	{
	while(*filedir !='')	{
		*filenamefix++ = *filedir++;
	}
	while(*filename !='')	{
		*filenamefix++ = *filename++;
	}
	*filenamefix++='.';
	*filenamefix++='x';
	*filenamefix++='d';
	*filenamefix++='i';
	*filenamefix++='f';
	*filenamefix++='f';
	*filenamefix='\0';
}

int _tmain(int argc, TCHAR *argv[])	 {
    HANDLE hFile;
	int retVal = 1;
    if( argc != 2 )	{
        retVal = 1;
		printf("%d",retVal);
		return retVal;
    }
	TCHAR* filepath = argv[1];
	TCHAR filedir[MAX_PATH];
	TCHAR filename[MAX_PATH];
	TCHAR filename_fix[MAX_PATH];
	SYSTEMTIME lastaccessnoted;
	BreakPath(filepath,filedir,filename);
	CreateDirectory( filedir , NULL );
	FixPath(filedir,filename,filename_fix);
	GetLastTimeAccess(lastaccessnoted, filename_fix );
    hFile = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL,OPEN_EXISTING, 0, NULL);

    if(hFile == INVALID_HANDLE_VALUE)	{
        retVal = 1;
		printf("%d",retVal);
		return retVal;;
    }
    if( (GetLastWriteTime( hFile, lastaccessnoted, filename_fix ) ))	 {
		retVal = 0;	// file same // not modified
		printf("%d",retVal);
		return retVal;;
	}
    CloseHandle(hFile);
	printf("%d",retVal);
	return retVal;
}

// edi ermawan // yogjakarta 27042013

// keywords: file modified  check, c++, c, Batch, incremental build

Written by XediXermawan

April 26, 2013 at 6:07 pm

Otomatisasi dengan script : windows powershell

with one comment

Kita mungkin pernah menjumpai orang-orang yang bekerja sangat cepat atau menyelesaikan banyak pekerjaan dengan waktu yang singkat, dan ada yang biasa saja dan bahkan mungkin lambat. Kenapa? Jawabannya mungkin : “orang kan beda-beda”, maksudnya? : “ada orang pintar dan ada orang bodoh”. :d, just kiddin’ . Yah, itu tentu tidak benar . Mungkin ada orang yang diberi kemampuan mengatur waktunya dengan baik & memiliki fokus yang tinggi dalam bekerja ( say NO to distraction ). Dan mungkin dia menggunakan “alat” yang benar dan cocok dalam menyelesaikan pekerjaan. Dan mungkin juga mereka menggunakan “magic” :-p, maksudku mereka mengotomatisasi pekerjaan. Kalau kita bekerja dengan komputer, banyak hal yang bisa di-otomatisasi.

Kita harus ingat, komputer dibuat dengan kelebihan antara lain: komputer bekerja sangat cepat dan dapat menyelesesaikan pekerjaan yang sama yang berulang-ulang. Dan tentu, tanpa rasa bosan ūüėÄ . Jadi jika kita mengerjakan pekerjaan yang sama dan berulang-ulang DI komputer, maka kemungkinan, kita masih belum bisa memaksimalkan fungsi komputer. Pekerjaan sebanyak mungkin harus bisa diotomatisasi. Bagaimana caranya? Banyak cara, namun saya lebih spesifik di blog post ini: menggunakan computer shell script/computer script/script. Script, sebuah source code yang bisa dijalankan tanpa harus dikompilasi dan di-linking, salah satu tools yang sangat membantu untuk mengotomatisasi pekerjaan. Terdapat banyak script yang bisa dipilih : python, lua, VBScript, DOS Batch, Bash, windows powershell , dll .

DOS Batch merupakan scripting pertama yang saya pelajari waktu belajar komputer di SMU dulu, dan juga belajar lagi waktu bekerja, karena Batch digunakan untuk membuat MAKE file. Batch bisa menyelesaikan banyak hal , namun Batch sangat prone-error . Selain Batch tidak ada lagi scripting yang saya pelajari . Python sempat menarik perhatian, namun belum mencobanya. Minggu lalu, saya menemukan kata “Windows Powershell” di sebuah buku, dan saya langsung tertarik untuk mempelajarinya. Mungkin karena “Power” disitu, sepertinya cool ūüėÄ . kalau kita membaca di Wiki, sepertinya memang benar-benar cool. Ok, saya mulai belajar, dengan motivasi “sepertinya cool” dan berharap bisa mengotomatisasi banyak pekerjaan dengan tool ini. Hehe . Windows Powershell di komputerku versi 3.0, dan ini versi terbaru. Untuk mendapat Windows Powershell prompt, cukup run Powershell.exe, misalnya saya run di directory N:\wpshell , command prompt sebagai berikut :

PS N:\wpshell>

seperti hal-nya scripting yang lain, kita bisa mengetik command langsung di command prompt atau menulis script di file lalu menjalankannya. Untuk menjalankan script , ada dua hal yang harus dilakukan , pertama men-settingexecution policy, karena nilai default-nya restricted, perlu di ubah sebagai berikut :

set-executionpolicy unrestricted

kedua, menjalankan script (misalnya script file diberi nama : testScript.ps1 ) sebagai berikut :

powershell -noexit “& “N:\wpshell\testScript.ps1”

Windows Powershell cukup mudah dipelajari, dan terdapat banyak resource di internet untuk mempelajarinya , seperti

http://technet.microsoft.com/en-us/library/hh848793.aspx

http://get-powershell.com/?page=2

http://www.powershellmagazine.com

Sebagai latihan, saya mencoba mencari beberapa masalah untuk saya selesaikan. Berikut masalah dan solusi yang saya coba ( ya , ini memang simple, tapi saya senang men-share disini )

#Case 1 : Mengganti banyak nama file

saya memiliki banyak foto dari camera, nama filenya tidak terlalu informatif DSCN0001.JPG, DSCN0002.JPG, dst. Saya ingin menggantinya dengan misalnya: LiburanTahunBaru_001, LiburanTahunBaru_002, dst. yaitu dengan format LiburanTahunBaru_NNN.JPG, dimana NNN adalah nomor index. Berikut script yang saya buat :

#source folder
$sourceFolder ="N:\Foto_Nikon_camera\Tita"
#header
$newNameHeader="LiburanTahunBaru_"

$a = $(Get-Item $sourceFolder\*.*)
$index=0
foreach ($i in $a)
{
	$newName =$newNameHeader + $index.ToString("000") + $i.Extension
	Rename-Item $i $newName
	$index += 1
}

#Case 2 : Mengelompokan file berdasarkan ekstensi

Internet browser ku adalah Google Chrome dan ketika saya mengunduh file, hasilnya ada di C:\Users\usenameku\Downloads, apapun jenis filenya semua masuk situ. Dan ketika folder tersebut mulai terisi banyak file dan daftar semakin memanjang, saya mulai memindah file berdasar file extension (.zip, .exe, .msi, etc. ) untuk mempermudah pencarian & kerapian. Saya lakukan secara manual. Poor habit. Dan yeah, ini bisa dilakukan secara otomatis dengan script :

#source folder
$sourceFolder ="C:\Users\usenameku\Downloads"
#header
$FolderHeader="\File"
#extension list
$extlist =@("zip", "rar","pdf","7z","jpg","png","exe","msi","mp3","wmv","mp4","flv","cpp","jar")
$index=0
#create folder if not exist
foreach ($i in $extlist)
{
	$newName =$sourceFolder + $FolderHeader + "_" + $i
	#check path existence
	if(Test-Path $newName)
	{
		#folder is already exist, do nothing
	}
	else
	{
		New-Item $newName -Type directory
	}
	$index += 1	
}
#get all items
$allitems = $(Get-Item $sourceFolder\*.*)
#move file to folder based on extension
foreach ($j in $extlist)
{
	$newName =$sourceFolder + $FolderHeader + "_" + $j
	foreach($k in $allitems)
	{
		if($k.Extension -eq ("."+$j))
		{
			if(Test-Path $k)
			{
				Move-Item $k $newName
			}
		}
	}
}

#Case 3 : Mengunduh RSS

Banyak website yang menyediakan fitur RSS, salah satunya Yahoo. Beberapa link RSS Yahoo :

         http://news.yahoo.com/rss/science

         http://news.yahoo.com/rss/entertainment

         http://news.yahoo.com/rss/health

         http://news.yahoo.com/rss/sports

         http://news.yahoo.com/rss/tech

         http://news.yahoo.com/rss/bussiness

         http://news.yahoo.com/rss/world

Dengan menggunakan link diatas kita bisa mendapatkan judul berita, link berita, dan isi berita, untuk pemrosesan lebih lanjut. Berikut script sederhana untuk mendapatkan judul dan link  dari RSS :

$docxml = [xml] (New-Object System.Net.WebClient).Downloadstring($url)
$stitle = $docxml.rss.channel.item.title
$slink = $docxml.rss.channel.item.link
$sitems = $docxml.rss.channel.item
foreach($sitem in $sitems)
{
	$sitem.title + "  -  " + $sitem.link >> link.txt
}

contoh hasil run :

Atom smasher hiatus sets stage for more discovery – http://news.yahoo.com/atom-smasher-hiatus-sets-stage-more-discovery-134311023.html

Spaceport wants protections from tourist lawsuits – http://news.yahoo.com/spaceport-wants-protections-tourist-lawsuits-213926570.html

#Case 4 : Mem-profil sebuah folder

Kadang saya ingin mengetahui apa yang membuat drive hardisk saya (misal drive D:\ ) penuh. Untuk mengeceknya saya perlu mengetahui folder dan file mana yang ukurannya besar ( memakan space ) . Jika info tersebut sudah didapat , maka bisa diambil keputusan:  folder atau file apa yang bisa di pindah/ di hapus.

$startFolder = "G:\testScriptCopy"

$colItems = (Get-ChildItem $startFolder | Measure-Object -property length -sum)
"$startFolder -- " + "{0:N2}" -f ($colItems.sum / 1MB) + " MB" >> report.txt
$fItems = $(Get-ChildItem $startFolder\*.* | Sort-Object -Property length -Descending)
foreach ($f in $fItems)
{
	"	"  + $f.Length + "   " + $f.Fullname >> report.txt
}

$colItems = (Get-ChildItem $startFolder -recurse | Where-Object {$_.PSIsContainer -eq $True} | Sort-Object)
foreach ($i in $colItems)
    {
        $subFolderItems = (Get-ChildItem $i.FullName | Measure-Object -property length -sum)
        $i.FullName + " -- " + "{0:N2}" -f ($subFolderItems.sum / 1MB) + " MB" >> report.txt
		$fsubItems = $(Get-ChildItem $startFolder\$i\*.* | Sort-Object -Property length -Descending)
		foreach ($fsub in $fsubItems)
		{
			"	"  + $fsub.Length + "   " + $fsub.Fullname >> report.txt
		}
    }

 

>> report.txt” menandakan kalau output disimpan ke file bernama report.txt. Jika “>> report.txt” dihilangkan ouput akan ditampilkan di command prompt.

#Case 5 : Akan diketemukan

Solution : akan diselesaikan

Saya menambah satu category di blog ini yaitu :¬†Scripting&Automation , akan di update disana. that’s plan ūüėÄ .

#yogyakarta , Jan 06  2013

Written by XediXermawan

January 6, 2013 at 4:50 pm