현재 cocos2d-x 3.4버전(ndk r10c)를 사용중인데

ios에서는 to_string사용이 가능하나

android빌드시 error: 'to_string' was not declared in this scope 에러를 뱉습니다.

ndk r10c에서는 to_string함수가 존재하지 않는듯 합니다.


다행히 cocos2d라이브러리 안에 아래의 주석코드가 있네요.

말대로 stringstream을 사용합시다.

    // std::to_string is not supported on android, using std::stringstream instead.


string to_string(int value)
{
    stringstream strStream;
    strStream<<value;
    return strStream.str();
}


위와 같이 사용을 해주시면 됩니다.

C++에서 C#함수를 호출하는 방법에 대해 포스팅하겠습니다.(곁다리로 C#에서 C++함수 호출하는 방법도...)


MonoPInvokeCallback를 사용하시면 됩니다.


in C# ↓↓↓

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
using AOT;

public class SomePlugin //어떤 플러그인입니다.
{
    public delegate void SomeCallback( string result ); // c++에서 호출해줄 Callback형입니다.

    public static extern void ConnectCallback (
SomeCallback someCallback); // c#에서 호출할 c++함수입니다.

    public SomePlugin()
    {
        ConnectCallback( SomeFunction ); // 생성자에서 c++함수를 호출합니다.
    }

    [MonoPInvokeCallback(typeof(
SomeCallback))] // 핵심입니다.
    public static void SomeFunction(string result)
    {
        //something...
    }
}


in C++ ↓↓↓

typedef void (*SomeCallback)(const char* result);
SomeCallback someCallback = NULL;

extern "C"
{
    void ConnectCallback(SomeCallback _someCallback) //c#에서 호출할 함수입니다.
    {
        someCallback = _someCallback;
    }
}

void SomeFunction(const char* result)
{
    if( someCallback != NULL )
        someCallback(result);
}



사용법은 함수포인터 쓰듯이 사용하시면 됩니다.다만 native code에서 액세스 할 수 있도록 MonoPInvokeCallback 속성을 적용해줘야합니다.

유니티에서는 비추천하는 방법입니다(함수 포인터가 주소값 접근이라 위험해서 그런건지 뭔지는 모르겠지만요). 추천하는 방법으로는 UnitySendMessage가 있는데 느린 특징을 가지고 있기에 저는 이 방법으로 해결했습니다.


Unity 빌드 시, 유의할 점

  1. Plugins 폴더
    • 빌드를 수행할 때, 자동으로 Plugins폴더 안의 Android, iOS 폴더안에 있는 "특정" 소스파일이나 리소스파일들을 프로젝트에 추가해줍니다. iOS같은 경우는 Header search path까지 연결해줍니다.
    • 문제는 한 프로젝트로 여러가지 빌드(서로 다른 플러그인을 사용하는)를 뽑을 때 문제가 된다는 것! 잘 삭제 해주지 않으면 쓸데없이 용량을 잡아먹게됩니다.(자동화할때 유의해주세요.)
  2. PostprocessBuildPlayer
    • Plugins 폴더에 넣어놓는다고 하더라도 "특정"파일만 넣는 성격때문에 누락되는 파일들이 있습니다. 손으로 넣어주시는 분들은 상관 없지만 자동화할 땐 엄청난 불편함으로 다가옵니다. 그럴때 이것을 사용합니다.(전 모듈로 mod_pbxproj.py를 사용합니다. 엄청 편해요~)
    • 문제는 Assets/Editor폴더 안에 있는 단 한개의 PostprocessBuildPlayer만 실행이 된다는것입니다. 사용할 PostprocessBuildPlayer들을 PostprocessBuildPlayer_*로 이름을 변경한 후, 메인 PostprocessBuildPlayer가 PostprocessBuildPlayer_*를 전부 찾아 실행해주면 됩니다.
    • 말로하니 복잡하네요. 아래의 소스코드를 참고해주세요.
===========================================================================

#!/usr/bin/python


import sys

import subprocess

import glob

import os


def main(argv):

    paths = glob.iglob( 'Assets/Editor/PostprocessBuildPlayer_*' )

    

    for path in paths:

        if os.path.splitext(path)[1] != '.meta':

            os.chmod( path, 0755 )

            subprocess.call( [os.path.realpath(path), sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]] )



if __name__ == "__main__":

    main(sys.argv)

===========================================================================


  • il2cpp
    1. 유니티에서 64bit지원을 위해 부랴부랴 내놓은 아이입니다. il2cpp로 빌드를 하시고 Architecture를 Universial 혹은 ARM64로 설정해 놓아야 64비트 지원이 됩니다.
    2. C#을 빌드하면 나오는 IL파일을 cpp파일로 변환해주는 역할을합니다. Classes 폴더 하위에 Native폴더가 생기네요. 그 안의 파일들을 둘러보긴 했지만... 여하튼 소스가 많이 생겼습니다.
    3. 문제점
      1. 일단 실행파일 용량이 늘어납니다.(소스량이 적다면 조금 늘어나거나 안늘어날 수도 있습니다.) 
      2. 컴파일 시간이 길어집니다.(Unity에서의 컴파일 시간은 의외로 느리지 않은데 xcode에서 빌드시 cpp파일을 전부 빌드해줘야하기 때문에 그로인해 컴파일 시간이 길어집니다.
      3. mono_domain같은 c++에서 c#함수를 가져다 사용할 수 있게해주는 함수를 사용하지 못합니다.
    4. 해결방안
      1. 늘어난 용량은 코드최적화 레벨을 올려주면(ex, strip assembly) 약간 줄어듭니다만 기대치는 낮습니다.
      2. 컴파일 시간은 그냥 감내해야된달까요....
      3. 해당 부분은 유니티에서 권장하는 UnitySendMessage를 사용하면 되지만 느립니다. Object와 함수명을 string으로 찾아서 사용하는 방식이기 때문에 빈번하게 불리는 환경이 아니면 이것을 사용해줍니다.
        1. 빈번하게 사용하는 환경이라면 MonoPInvokeCallback를 사용해줍니다.




예전에 만들었던 인앱 콜백을 통해 예를 들겠습니다.



선언

std::function<void(std::string productID, bool success)> inappRequestCallback;


std::function<return_type(arguments,..)> 형태로 변수를 선언합니다.

위의 예제에서는 인앱의 productID와 성공여부를 넘겨받습니다.



사용


void StoreLayer::BuyTest(string productID, bool success)

{

}



inappRequestCallback = bind(&TitleLayer::BuyTest, this, "", true);

inappRequestCallback();

or

inappRequestCallback = bind(& StoreLayer::BuyTest, storeLayer, placeholders::_1, placeholders::_2);

inappRequestCallback("", true);


bind함수를 통해 delegate(callback)를 등록시킵니다.

인자에 대해 두가지 방법으로 세팅할 수 있는데

하나는 미리 넘겨줄 인자를 등록시켜놓는 것이고, 나머지 하나는 등록시키지 않는 것 입니다.

미리 넘겨줄 인자를 등록시켜놓은 경우,
함수 사용시, 어떤 값을 넘겨주어도 이전에 등록시켰던 인자가 전달됩니다.

하지만 placeholders를 이용하면 미리 인자를 등록시키지 않고 함수 사용시 인자를 전달 할 수 있습니다.

grep 명령어 사용법

grep 명령어

grep의 의미

grep : 파일 전체를 뒤져 정규표현식에 대응하는 모든 행들을 출력한다.
egrep : grep의 확장판으로, 추가 정규표현식 메타문자들을 지원한다.
fgrep : fixed grep 이나 fast grep으로 불리며, 모든 문자를 문자 그래도 취급한다. 즉, 정         규표현식의 메타문자도 일반 문자로 취급한다.

3.1.2 grep의 동작 방법

grep에서 사용하는 정규표현식 메타문자

메타문자
기    능
사용 예
사용 예 설명
^
행의 시작 지시자
'^love'
love로 시작하는 모든 행과 대응
$
행의 끝 지시자
'love$'
love로 끝나는 모든 행과 대응
.
하나의 문자와 대응
'l..e'
l 다음에 두 글자가 나오고 e로 끝나는 문자열을 포함하는 행과 대응
*
선행문자와 같은 문자의 0개 혹은 임의개수와 대응
' *love'
0개 혹은 임의 개수의 공백 문자 후에 love로 끝나는 문자열을 포함한 행과 대응
[]
[] 사이의 문자 집합중 하나와 대응
'[Ll]ove'
love나 Love를 포함하는 행과 대응
[^ ]
문자집합에 속하지 않는 한 문자와 대응
'[^A-K]love'
A와 K 사이의 범위에 포함되지 않는 한 문자와 ove가 붙어있는 문자열과 대응
\<
단어의 시작 지시자
'\<love'
love로 시작하는 단어를 포함하는 행과 대응(vi,grep에서 지원)
\>
단어의 끝 지시자
'love\>'
love로 끝나는 단어를 포함하는 행과 대응 
(vi,grep에서 지원)
\(..\)
다음 사용을 위해 태그를 붙인다.
'\(lov\)ing'
지정된 부분을 태크1에 저장한다. 나중에 태그값을 참고하려면 \1을 쓴다. 맨 왼쪽부터 시작해 태그를 9개가지 쓸 수 있다. 왼쪽 예에서는 lov가 레지스터1에 저장되고 나중에 \1로 참고할 수 있다.
x\{m\}
문자 x를 m번 반복한다.
'o\{5\}'
문자 o가 5회 연속적으로 나오는 모든 행과 대응
x\{m,\}
적어도 m번 반복한다.
'o\{5,\}'
문자 o가 최소한 5회 반복되는 모든 행과 대응
x\{m,n\}
m회 이상 n회 이하 반복한다.
o\{5,10\}'
문자 o가 5회에서 10회 사이의 횟수로 연속적으로 나타나는 문자열과 대응

grep의 옵션

옵션
동작 설명
-b
검색 결과의 각 행 앞에 검색된 위치의 블록 번호를 표시한다. 검색 내용이 디스크의 어디쯤 있는지 위치를 알아내는데 유용하다.
-c
검색 결과를 출력하는 대신, 찾아낸 행의 총수를 출력한다.
-h
파일 이름을 출력하지 않는다.
-i
대소문자를 구분 하지 않는다.(대문자와 소문자를 동일하게 취급).
-l
패턴이 존재하는 파일의 이름만 출력한다.(개행문자로 구분)
-n
파일 내에서 행 번호를 함께 출력한다.
-s
에러 메시지 외에는 출력하지 않는다. 종료상태를 검사할 때 유용하게 쓸 수 있다.
-v
패턴이 존재하지 않는 행만 출력한다.
-w
패턴 표현식을 하나의 단어로 취급하여 검색한다.

# grep -n '^jack:' /etc/passwd
(/etc/passwd 파일에서 jack을 찾는다. jack이 행의 맨 앞에 있으면 행 번호를 화면으로 출력한다.)

3.1.3 grep과 종료 상태
grep은 파일 검색의 성공 여부를 종료 상태값으로 되돌려준다.
패턴을 찾으면 0, 패턴을 찾을 수 없으면 1, 팡리이 존재하지 않을 경우 2
sed,a자 등은 검색의 성공 여부에 대한 종료 상태값을 반환하지 않는다. 다만 구문 에러가 있을 경우에만 에러를 보고한다.

3.2 정규표현식을 사용하는 grep의 예제
# grep NW datafile
# grep NW d*
(d로 시작하는 모든 파일에서 NW를 포함하는 모든 행을 찾는다.)
# grep '^n' datafile
(n으로 시작하는 모든 행을 출력한다.)
# grep '4$' datafile
(4로 끝나는 모든 행을 출력한다.)
# grep TB Savage datafile
(TB만 인자이고 Savage와 datafile은 파일 이름이다.)
# grep 'TB Savage' datafile
(TB Savage를 포함하는 모든 행을 출력한다.)
# grep '5\.' datafile
(숫자 5, 마침표, 임의의 한 문자가 순서대로 나타나는 문자열이 포함된 행을 출력한다.)
# grep '\.5' datafile
(.5가 나오는 모든 행을 출력한다.)
# grep '^[we]' datafile
(w나 e로 시작하는 모든 행을 출력한다.)
# grep '[^0-9]' datafile
(숫자가 아닌 문자를 하나라도 포함하는 모든 행을 출력한다.)
# grep '[A-Z][A-Z] [A-Z]' datafile
(대문자 2개와 공백 1개, 그리고 대문자 하나가 연이어 나오는 문자열이 포함된 행을 출력한다.)
# grep 'ss* ' datafile
(s가 한 번 나오고, 다시 s가 0번 또는 여러번 나온 후에 공백이 연이어 등장하는 문자열을 포함한 모든 행을 출력한다.)
# grep '[a-z]\{9\}' datafile
(소문자가 9번 이상 반복되는 문자열을 포함하는 모든 행을 출력한다.)
# grep '\(3\)\.[0-9].*\1 *\1' datafile
(숫자 3,마침표,임의의 한 숫자,임의 개수의 문자,숫자 3(태그),임의 개수의 탭 문자,숫자 3의 순서를 갖는 문자열이 포한된 모든 행을 출력한다.)
# grep '\<north' datafile
(north로 시작하는 단어가 포함된 모든 행을 출력한다.)
# grep '\<north\>' datafile
(north라는 단어가 포함된 모든 행을 출력한다.)
# grep '\<[a-z].*n\>' datafile
(소문자 하나로 시작하고, 이어서 임의 개수의 여러 문자가 나오며, n으로 끝나는 단어가 포함된 모든 행을 출력한다. 여기서 .*는 공백을 포함한 임의의 문자들을 의미한다.)

3.3 grep에 옵션 사용
# grep -n '^south' datafile
(행번호를 함께 출력한다.)
# grep -i 'pat' datafile
(대소문자를 구별하지 않게 한다.)
# grep -v 'Suan Chin' datafile
(문자열 Suan Chin이 포함되지 않은 모든 행을 출력하게 한다. 이 옵션은 입력 파일에서 특정 내용의 입력을 삭제하는데 쓰인다.
# grep -v 'Suan Chin' datafile > black
# mv black datafile
)
# grep -l 'SE' *
(패턴이 찾아진 파일의 행 번호 대신 단지 파일이름만 출력한다.)
# grep -w 'north' datafile
(패턴이 다른 단어의 일부가 아닌 하나의 단어가 되는 경우만 찾는다. northwest나 northeast 등의 단어가 아니라, north라는 단어가 포함된 행만 출력한다.)
# grep -i "$LOGNAME" datafile
(환 경변수인 LOGNAME의 값을 가진 모든 행을 출력한다. 변수가 큰따옴표로 둘러싸여 있는 경우, 쉘은 변수의 값으로 치환한다. 작은따옴표로 둘러싸여 있으면 변수 치환이 일어나지 않고 그냥 $LOGNAME 이라는 문자로 출력된다.)

3.4 egrep
egrep(extended grep) : grep에서 제공하지 않는 확장된 정규표현식 메타문자를 지원  한다.
                                     grep와 동일한 명령행 옵션을 지원한다.
egrep에서 지원하는 확장 메타문자

메타문자
기능
사용 예
사용 예 설명
+
선행문자와 같은 문자의 1개 혹은 임의 개수와 대응
'[a-z]+ove'
1개 이상의 소문자 뒤에 ove가 붙어있는 문자열과 대응. move,approve,love,behoove 등이 해당된다.
?
선행문자와 같은 문자의0개 혹은 1개와 대응
'lo?ve'
l 다음에 0개의 문자 혹은 하나의 문자가 o가 나오는 문자열과 대응. love,lve 등이 해당된다.
a|b
a 혹은 b와 대응
'love|hate'
love 혹은 hate와 대응.
()
정규표현식을 묶어준다
'love(able|ly)'
lovable 혹은 lovely와 대응.
'(ov)+'
ov가 한 번 이상 등장하는 문자열과 일치.

3.4.1 egrep 예제
# egrep 'NW|EA' datafile
(NW나 EA가 포함된 행을 출력한다.)
# egrep '3+' datafile
(숫자 3이 한 번 이상 등장하는 행을 출력한다.)
# egrep '2\.?[0-9]' datafile
(숫자 2 다음에 마침표가 없거나 한 번 나오고, 다시 숫자가 오는 행을 출력한다.)
# egrep ' (no)+' datafile
(패턴 no가 한 번 이상 연속해서 나오는 행을 출력한다.)
# egrep 'S(h|u)' datafile
(문자 S 다음에 h나 u가 나오는 행을 출력한다.)
# egrep 'Sh|u' datafile
(패턴 Sh나 u를 포함한 행을 출력한다.)

3.5 고정 grep 과 빠른 grep
fgrep : grep 명령어와 동일하게 동작한다. 다만 정규표현식 메타문자들을 특별하게 취급하지
          않는다.
# fgrep '[A-Z]****[0-9]..$5.00' file
([A-Z]****[0-9]..$5.00 이 포함된 행을 출력한다. 모든 문자들을 문자 자체로만 취급한다.)


==============================================================================================
grep 명령어

◈ 기본문법

grep [-civnlw] pattern file_name1 [file_name2]

-c    패턴이 일치하는 행의 수를 출력
-i     배교시 대소문자를 구별하지 않음
-v    지정한 패턴과 일치하지 않는 행만 출력
-n    행의 번호를 함께 출력
-l     패턴이 포함된 파일의 이름을 출력
-w   패턴이 전체 단어와 일치하는 행만 출력

◈ 정규표현식 사용 예

^freeman       freeman으로 시작하는 행
freeman$       freeman으로 끝나는 행
freema*         freema로 시작하는 단어
f.....n            f로 시작하고 n으로 끝나는 7자리 단어
[a-d]           a,b,c,d로 시작하는 단어
[fF]reeman   freeman또는 Freeman으로 시작하는 단어

◈ 사용 예

$ grep Sunny grep.data         --> Sunny가 들어 있는 행을 출력
$ grep -n Sunny grep.data     --> Sunny가 들어 있는 행을 번호와 함께 출력
$ grep '^S' grep.data             --> 첫문자가 S로 시작하는 행을 출력
$ grep 'Thank you' grep.data  --> 문자열 Thank you가 들어 있는 행을 출력

--------------------------------------------------------------------------------------------------------


find 명령어

◈ 기본문법
find path [expression] [action]

-name file_name          검색 대상 파일명을 입력. 파일명으로 [], ? * 의 메타문자를 사용할 수 있음.
-type [file_type]          검색 대상 파일의 종류를 지정.  b(Block), c(Character), d(Directory), p(Named Pipe)
                                                                      f(Regular File), l(Symbolic Link), s(Socket)
-user uname               uname은 검색 파일의 소유주 또는 UID.
-group gname             gname은 검색 파일의 소유그룹 또는 GID.
-size [+-]num[bck]     검색 파일의 크기를 지정.  num(일치), +num(이상), -num(이하)
                                                               b(Block,512Byte), c(Byte), k(KByte)
-perm mode                주어진 접근 권한을 갖는 파일을 검색. (8진수로 기술)
-atime [+-]n               파일이 읽힌 최근 시간
-ctime [+-]n               파일의 소유주나 권한이 바뀐 최근 시간
-mtime [+-]n               파일이 수정된 최근 시간
-prune                       서브 디렉토리로 내려가지 않고 현재 디렉토리에서만 검색
-print                         검색 후에 행할 작업 옵션 : 검색결과 출력
-exec command {}\;   검색 후에 행할 작업 옵션 : 결과에 특정 명령을 실행하도록 명령


◈ 사용 예
$ find .  --> -print옵션은 일반적으로 디폴트이다. 따라서 'find . '은 'find . -print'와 같다.

$ find . -name "*.c" -print
$ find . -name "ip*.c" -print --> ip로 시작하며 확장자가 .c로 끝나는 파일 검색

$ find . -type d -print        --> 현재 디렉토리 하위(서브 포함)에서 디렉토리를 찾아 표시
$ find . -name lib -type d  --> 현재 디렉토리 하위(서브 포함)에서 lib라는 이름의 디렉토리 표시

$ find . -size +56 -print                         --> 파일 크기가 56블록보드 큰 것을 검색
$ find . -size +800c -size -900c -print    --> 파일 크기가 800Byte보다 크고 900Byte보다 작은 것을 검색

$ find . -perm -1 -print   --> other에 실행권한이 있는 파일 검색. 1은 '--------X'를 의미
$ find . -perm -44 -print  --> group에 읽기권한, other에 읽기권한이 있는 파일 검색
$ find . -perm 664 -print  --> user와 group에 읽기와 쓰기 권한, other에 읽기권한이 있는 파일 검색

$ find . -mtime +3 -print  --> 수정한지 3일이 지난 파일을 검색(5일~)
$ find . -mtime 3 -print   --> 수정한지 3일이 된 파일을 검색
$ find . -mtime -3 -print  --> 수정한지 3일이 못된 파일을 검색(0,1,2일)

$ find . -name "*.o" -print
$ find . -name "*.o" -exec rm {} \; --> .o 파일을 찾아서 그 결과를 rm명령어 실행시 인수로 전달
$ find . -name "*.o" | wc -l            --> .o 파일을 찾아서 파이프로 그 결과를 wc명령의 입력으로 전달

※ fine는 논리 연산이 가능하다
  -a (And),  -o (Or),  ! (Not)

$ find . -name "*.log" -o -name "*.o" -print                        --> 확장자가 '.log'이거나 '.o'인 것을 검색
$ find . \( -name "*.log" -o -name "*.o" \) -print              --> 위와 동일. '('를 사용하려면 '\'을 붙여야 함
$ find . ! \( -name "*.log" -o -name "*.o" \) -print            --> 괄호 사용으로 이렇게 전체부정등이 가능
                                                                                   '.log'와 '.o' 이외의 파일을 검색
$ find . \( -name "*.log" -o -name "*.o" \) -exec rm {} \;  --> '.log'나 '.o'인 것을 찾아 삭제
 --------------------------------------------------------------------------------------------------------xargs 명령어 

find . | xargs 를 하면 find명령의 결과가 한 행으로 출력된다. 즉, xargs는 여러행을 한행으로 만드는 역할을 한다.

$ find . -name "*.c" -exec grep test {} \;
$ find . -name "*.c" | xargs grep test

첫번째 명령은 find을 결과가 여러행일 때, 그 행의 수만큼 grep명령어를 실행한다.
두번째 명령은 find의 결과를 xargs가 한 행으로 만들어 grep에 전달하므로 grep는 한번만 실행된다.

◈ 사용 예
$ find . \(-name "*.log" -o -name "*.o"\) | xargs rm  --> .log와 .o 파일을 찾아서 삭제
$ find . -name *.php -exec chmod 755 {} \;  --> .php파일을 찾아서 접근권한을 755로 변경. chmod 매번 실행
$ find . -name *.php | xargs chmod 755         --> 위와 같음. chmod 한번 실행
$ find . | xargs grep -l "freeman" | xargs rm    --> freeman이라는 문자열을 포함한 파일을 찾아서 지움

출처 : http://lkrox.blogspot.kr/2013/01/grep.html


rmdir을 이용하면 폴더 삭제가 가능하지만

폴더 하위에 내용물이 있을 경우 안되더군요.(-f(force) 도 안됨)


그런 경우에는 rm -rf [폴더명]을 사용하면 됩니다.

'Notes > Tech History' 카테고리의 다른 글

Windows NTSTATUS 코드 전체 표 (STATUS_ 에러 코드 정리)  (0) 2019.01.02
grep 명령어  (0) 2015.03.20
zip 명령어  (0) 2015.03.20
프로그래밍 언어 순위  (0) 2012.02.02
파일 입출력, 파일 포인터(FILE* fp)  (0) 2012.01.02

zip 명령어


zip [destination] [source]


-r  : 하위 폴더까지 전부 압축


source에 폴더 경로(ex : a/b/c)로 할 경우, 폴더 경로까지 전부 압축됩니다.

해결법을 못찾아서 cd로 우회

'Notes > Tech History' 카테고리의 다른 글

grep 명령어  (0) 2015.03.20
command line에서 폴더 삭제  (0) 2015.03.20
프로그래밍 언어 순위  (0) 2012.02.02
파일 입출력, 파일 포인터(FILE* fp)  (0) 2012.01.02
싱글턴 클래스  (0) 2011.10.17

준비물

Jenkins서버

SVN서버(저장소)


* 필자의 SVN서버와 Jenkins 서버는 서로 다르기 때문에 그것을 중심으로 설명하겠습니다.


1. Jenkins를 커맨드라인에서 사용하기

https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI 에 들어가보면 Jenkins.war안에 Jenkins-CLI.jar가 있다고 하는데.... 아무리 찾아봐도 없습니다. 그래서 Jenkins 설정창을 들어가보니 떡하니 위에서 8번째에 존재하는 Jenkins CLI라는 항목!

들어가서 Jenkins CLI 설명을 보고 svn서버에서 Jenkins-CLI.jar를 다운받습니다.

'BackEnd · DevOps > CI · CD' 카테고리의 다른 글

Symbol Server 설정  (0) 2018.03.12
젠킨스에서 IOS빌드 및 배포  (0) 2015.02.26
Jenkins에서 Unity 빌드하기  (1) 2015.01.26

젠킨스의 해당 잡에서 build에 excute shell을 추가합니다.


xcode 빌드는 xcodebuild라는 녀석을 통해합니다.

xcodebuild는 xcode에서 commandline tool을 설치하면 됩니다. (preference에 있습니다.)

xcodebuild -project "프로젝트의 상대경로.xcodeproj" -configuration "Release or Debug or anything else" -scheme 스킴이름 clean archive -archivePath "생성할 xcarchive 상대경로.xcarchive"

xcodebuild -exportArchive -exportFormat ipa -archivePath "위에서 생성한 xcarchive 상대경로.xcarchive" -exportPath "생성할 ipa 상대경로.ipa" -exportProvisioningProfile "프로비져닝프로파일 이름"


프로비져닝 제대로 세팅을 안하면 ipa가 설치되는 것처럼 보여도 마지막에 실패하는 문제가 발생합니다.


ipa를 웹에서 설치하도록 하는 방법


1. plist를 생성

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0"> <dict>

<key>items</key>

<array><dict>

<key>assets</key>

<array><dict>

<key>kind</key><string>software-package</string>

<key>url</key><string>ipa URL</string>

</dict></array>

<key>metadata</key>

<dict>

<key>bundle-identifier</key><string>bundle identifier</string>

<key>bundle-version</key><string>bundle version</string>

<key>kind</key><string>software</string>

<key>title</key><string>product name</string>

</dict>

</dict></array>

</dict></plist>

1. 위와 같이 plist파일을 생성

2. ipa URL을 입력

3. bundle identifier를 입력

4. bundle version를 입력

5. product name을 입력

6. 생성한 plist파일을 https서버에 업로드(ex : 드랍박스, etc...)


2. 아이폰의 사파리에서 아래의 주소를 입력합니다.

itms-services://?action=download-manifest&url=https://dl.dropboxusercontent.com/s/aej12jdnkc/myapp.plist

(plist파일만 https서버 상에 올라가있으면 됩니다.)

목적 : CI를 통해  Unity빌드를 자동화 한다.


필요한 것

Unity pro

SVN

Jenkins

JDK(jenkins설치시 필요)

Jenkins의  unity build plugin


진행 과정

0. 젠킨스 설치

0-1. jenkins를 다운로드 후, 설치를 하면 Applications(응용 프로그램)/Jenkins/jenkins.war가 생성된다.

0-2. terminal에서 jenkins.war의 디렉터리로 이동 후, $java -jar jenkins.war 명령을 실행한다.

0-3. 사파리에서 localhost:8080으로 접속한다.

 - Default port번호는 8080 변경하고 싶으면 --httpPort=번호 로 바꿔준다.

1. 시스템 설정을 한다.

1-1. JDK Installations

 - mac에서 JAVA_HOME은 JDK설치 후 /usr/libexec/java_home을 실행하면 알 수 있음

1-2 ANT Installations(있으니까 했음, Maven연동은 안한)

1-3 unity build plugin을 설치하면 Maven아래쪽에 Unity3d탭이 생김 Untiy installations를 등록

 - mac에서 발생하는 Not Unity3d home directory /Applications/Unity 에러가 뭔지 모르겠음.

 => 발견 : Installation directory를 /Applications/Unity/Unity.app으로 해야됨

2. Configure Global Security

2-1. Enable security 활성화

2.2. Security Realm의 Access Control에서 Jenkins'own user database 활성화 및 사용자의 가입 허용 활성화

2.3 Autorization에서 Project-based Matrix Authorization Stratgy 활성화

 => 젠킨스 세팅 완료


3. 새로운 Item(Job 등록)

3-1. 새로운 Item클릭 후, Freestyle project 생성

3-2. 소스 코드 관리에서 Subversion선택

 - Unable to access svn://blah.blah.blah.blah/svn/what/what : svn:E200015:No credential to try. Authentication failed(show details) (Mabe you need to enter credential?) 에러 발생시에는 enter credential을 클릭 후, subversion Authentication을 등록하면 된다.

3-3. Build탭에서 Invoke Unity3d Editor에서 Unity3d installation name을 아까 시스템 설정창에서 등록한 유니티로 설정.

3-4. Editor command line arguments을 채움

 - -quit -batchmode -project Path "/Path/path/Path/path/path" -executeMethod className.methodName -output  "%WORKSPACE%\output" -Define PREDEFINES로 했음

- http://docs.unity3d.com/Manual/CommandLineArguments.html 참조


이제 실행시키면 됨.


빌드 시, 문제 발생

해당 빌드 콘솔에서 FAILED TO establish the default connection to the WindowServer가 뜨고 아무것도 안되는 경우,

sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist

sudo mv /Library/LaunchDaemons/org.jenkins-ci.plist /Library/LaunchAgents/

를 입력하면 젠킨스가 종료됩니다. 이후, 젠킨스를 실행해주면 잘 됩니다.



using UnityEngine;

using System;

using System.IO;

using System.Collections;

using System.Collections.Generic;

using UnityEditor;


public class CommandBuild

{

static Dictionary<string, string> arguments = new Dictionary<string, string>();

static void InitCommandLineArgs()

{

string[] commandArgs;

if (editorBuild != null)

commandArgs = editorBuild.Split(' ');

else

commandArgs = Environment.GetCommandLineArgs();


for (int i = 0; i < commandArgs.Length; i++)

{

if (commandArgs[i].Length > 1 && commandArgs[i].StartsWith("-"))

{

string key = commandArgs[i].Substring(1);

if (arguments.ContainsKey(key) == false)

{

string value = null;

if (i + 1 < commandArgs.Length)

value = commandArgs[i + 1];

arguments.Add(key, value);

}

}

}

}

public static void BuildAndroid()

{

InitCommandLineArgs();


string define = GetValue("Define");

if (define != null)

PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, define);


string outputFileName = GetValue("outputFileName");

string savepath = string.Format("{0}/../{1}.apk", Application.dataPath, outputFileName);

PlayerSettings.Android.keystoreName = "keystoreName.keystore";

PlayerSettings.Android.keyaliasName = "keyaliasName";

PlayerSettings.Android.keystorePass = "keystorePass";

PlayerSettings.Android.keyaliasPass = "keyaliasPass";


Build(savepath, BuildTarget.Android);

}


public static void BuildiOS()

{

InitCommandLineArgs();

string define = GetValue("Define");

if (define != null)

PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iPhone, define);

string outputFileName = GetValue("outputFileName");

string savepath = string.Format("{0}/../"+outputFileName, Application.dataPath);


Build(savepath, BuildTarget.iPhone);

}




이후 발견된 버그

1. 플랫폼 변경이 안된채로 빌드되는 경우

=> 플랫폼 변경하는 코드를 삽입하여도 실질적으로 코드와 연결된 라이브러리들이 변경전 라이브러리들을 보고 있어서 컴파일 에러 발생

해결 : 빌드 과정을 하나 상단에 추가하여 플랫폼 변경을 미리 해준 후, 다음 빌드 과정에서 빌드를 해준다.

2. Definition이 변경 안되는 경우

=> preprocess defininition들을 위의 소스와 같이 변경을 해도 적용이 안되는 버그 발생

해결 : 1번과 같이 prebuild를 만들어 그 안에서 빌드전에 세팅해야할 것들을 미리 세팅한다.