Jenkins를 활용하여 MFC(Window app) 프로그램의 CI/CD환경을 구성한다.

1. Jenkins에 svn, msbuild 플러그인 설치

2. MSBuild 설정

3. svn 계정설정.

4. Item(Job)생성
5. Tag별로 빌드 구성

 

Jenkins 관리 -> 플러그인 관리
설치 가능 선택 후 "subversion" 검색하여 항목 선택 후 "Install after restart"
MSBuild 검색 후 설치 
Jenkins 관리 -> Global Tool Configuration.
MSBuild가 설치된 경로 설정 후 SAVE
New Item 생성 -> 이름입력, FreeStyle project "OK"
General 상단에 이 빌드는 매개변수가 있습니다. 체크 후 List Subversion Tags 선택
Credentials->add를 눌러서 SVN계정 추가
소스 코드 관리에서 Subversion 설정

Repository URL, svn 주소 CI/CD는 지속 통합 지속 배포가 목적이기에 배포목적인 tag경로를 설정한다.

위에 매개변수로 설정한 rel_version을 사용하는 경로로 지정한다.

Tags 디렉토리 구조가 아래와 같으면

Tags - rel_v2/client/projects/project1/project1.sln

      └ rel_v3

      └ rel_v4

      └ rel_v5...

 

rel_v2/client/projects/project1/project1.sln의 빌드 설정

MSBuild version은 사전에 설정해둔 msbuild 설정을 선택.

MSBuild Build File에는 빌드할 프로젝트 파일 경로

Command Line Arguments: MSBuild 옵션이며 스크린샷과 같이 실행 시 Win32(x86), Release로 Rebuild 실행한다. 

저장 후  Build With Parameters 선택해서 정상적으로 빌드진행이 되는지 테스트가 가능한다.

매개변수 선택 combobox에 tag 버전 리스트를 선택후 빌드하기를 눌러 진행한다.

최초 진행시 workspace에 svn checkout 을 받으면서 시간이 오래걸린다. 

또, 빌드의 Console Output 으로 진행상태 확인이 가능하다.

MFC로 프로그램을 만들고 보면 이런 경우가 종종있다.


Debug로 했을때는 프로그램이 안뻗는다, 릴리즈로 돌렸을때 뻗는 경우.


이때 가장 먼저 하는게 resource.h 에 중복되는 숫자를 제거하는 방법이지만,


이걸로 안돼면 이 디버그 메시지가 있는지 확인해야한다.


... 첫번째 예외가 발생하였습니다 ...

혹은

... First-Chance exception ...


이 메시지는 잠재적인 문제를 알려주는 것인데, 보통에는 문제가 없어서 지나가기 쉽다.


이 메시지를 디버깅 하기위해서는 환경설정의 디버그 -> 예외 에서 모든 예외 상황을 브레이킹하게 설정해서


디버깅할 수 있다. Access violation 체크!


단축키로는 ctrl + alt + E 를 누른다.





이미지에 표시된 항목을 체크하면 첫번째 예외 메시지가 출력되는 상황에서 디버깅이 걸릴 것이다.






목표: 
       CD/ MP3 플레이어를 스왑형식으로 만든다.
       재생, 정지, 일시정지, 앞곡, 뒷곡, 랜덤, 반복 기능
       리스트 곡 목록 확인 할 수 있도록.

CD의 재생관련된 제어를 담당할 클래스.
MP3파일의 재생관련된 제어를 담당할 클래스.

ListControl에 재생될 곡들을 담당할 클래스.


이 세개의 클래스를 만들어 사용.


라이브러리는 MCI 를 사용할 것이다.


출처 -> www.codein.co.kr  프로그래머의 놀이터 (Code人)

 

MFC의 직렬화(Serialize)를 사용해, 오브젝트을 파일에 쓰고 읽는 방법에 대해 살펴보겠습니다.


소개할 기능은 기본적으로, 오브젝트의 현재 상태를 파일에 보존하거나 복원 하는 기능입니다.

 

1) MFC AppWizard를 사용해, 다이얼로그 기반의 프로젝트를 작성합니다.
메인 다이얼로그에 아래와 같이 컨트롤을 배치합니다.


(여기에서는, 프로젝트명을 Serialize Test 로서 작성했습니다.)

사용자 삽입 이미지

2) 새로운 클래스를 생성합니다.

클래스타입은 "Generic Class", 클래스명은 "CNewData" 이고, 부모클래스로 "CObject"를 지정합니다.

OK 버튼을 클릭해서, 클래스를 생성합니다.

사용자 삽입 이미지

 

// MyData.h

class CMyData : public CObject 
{
    DECLARE_SERIAL( CMyData)    // 직렬화 선언
public:
    CMyData();
    virtual ~CMyData();

    // 다음함수(Serialize)를 오버라이딩
    virtual void Serialize( CArchive& archive );

    int m_nValue;        // 값1: 다이얼로그의 "IDC_EDIT1"에 해당
    CString m_strValue;  // 값2: 다이얼로그의 "IDC_EDIT2"에 해당
};

 

// MyData.cpp
#include "stdafx.h"
#include "SerializeTest.h"
#include "MyData.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// 직렬화선언

IMPLEMENT_SERIAL( CMyData, CObject, 1)
////////////////////////////////////////////////////////
// Construction/Destruction

////////////////////////////////////////////////////////

CMyData::CMyData()
{
   //멤버변수 초기화

    m_nValue = 0;
}

CMyData::~CMyData()
{

}

// Serialize 함수를 오버라이딩(재정의)
void CMyData::Serialize( CArchive& ar)
{
    // 부모클래스의 함수를 호출
    CObject::Serialize( ar);


    // 이클래스의 데이터를 보존
    if( ar.IsLoading() == TRUE)
    {
        // 읽어올때
        ar >> m_nValue >> m_strValue;
    }
    else
    {
        // 저장할때
        ar << m_nValue << m_strValue;
    }
}

다이얼로그 내용의 저장, 읽어오기 버튼의 클릭 이벤트 핸들러를 작성합니다.
(다이얼로그의 버튼상에서 더블 클릭)
아래와 같은 내용을 기술합니다.

 

// MyData.cpp: 
//
///////////////////////////////////////////////////////
#include "MyData.h"

// 저장버튼 클릭시

void CSerializeTestDlg::OnButton1() 
{
    // TODO:

    BOOL bret;
    // 화면에 입력된 내용을 읽어서, 파일에 저장

    CMyData data;
    int nValue;
    CString strValue;


    // 값1은、int형으로 보존
    nValue = (int)GetDlgItemInt( IDC_EDIT1);
    GetDlgItemText( IDC_EDIT2, strValue);

    data.m_nValue = nValue;
    data.m_strValue = strValue;

   

    // 파일을 쓰기모드로 오픈

    CFile f;
    bret = f.Open( "C:\\Temp\\MyData.dat", 
            CFile::modeCreate | CFile::modeWrite);
    if( bret == FALSE)
    {
        AfxMessageBox( "파일열기 실패");
        return;
    }


    CArchive ar( &f, CArchive::store);
    TRY
    {
        data.Serialize( ar);
    }
    CATCH_ALL( e)
    {
        AfxMessageBox( "보존에러");
    }
    END_CATCH_ALL;

   

   ar.Close();
    f.Close();

    // 화면내용을 초기화

    SetDlgItemText( IDC_EDIT1, "");
    SetDlgItemText( IDC_EDIT2, "");

}


// 읽어오기 버튼 클릭시
void CSerializeTestDlg::OnButton2() 
{
    // TODO:

    // 파일을 엽니다.
    BOOL bret;
    CFile f;
    bret = f.Open( "C:\\Temp\\MyData.dat", CFile::modeRead);
    if( bret == FALSE)
    {
        AfxMessageBox( "파일열기 실패");
        return;
    }

    CMyData data;

    CArchive ar( &f, CArchive::load);
    TRY
    {
        data.Serialize( ar);
    }
    CATCH_ALL( e)
    {
        AfxMessageBox( "보존에러");
    }
    END_CATCH_ALL;

 

   ar.Close();
    f.Close();

    // 화면에 출력

    SetDlgItemInt( IDC_EDIT1, data.m_nValue);
    SetDlgItemText( IDC_EDIT2, data.m_strValue);

}

 

정리하면,

1) 화면의 내용을 읽어와서 CMyData의 멤버변수에 저장합니다. 그리고, CMyData 객체의 내용(멤버변수)을 파일에 저장합니다.

2) 파일을 열어서 저장된 내용을 가져온후, 이를 CMyData 객체의 내용으로 채웁니다

+ Recent posts