<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개인공간</title>
    <link>https://stackov.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 26 May 2026 16:47:22 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>후유증</managingEditor>
    <item>
      <title>[Linux] rbash - 사용자 명령어 사용 제한</title>
      <link>https://stackov.tistory.com/68</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스 설치시 기본적으로 제공되는 쉘 &lt;code&gt;bash&lt;/code&gt; 에서는 특정 사용자의 명령어를 제한하기 위한 기능이 존재하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;code&gt;/bin/&lt;/code&gt; 에 설치된 바이너리의 경우 퍼미션을 지정을 통해 사용자 접근 제한이 가능하나, 세부적으로 사용자별 접근 제한이 가능하지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이를 해결하기 위해선 &lt;code&gt;bash&lt;/code&gt;에서 &lt;code&gt;restricted shell&lt;/code&gt; 기능을 지원하며, 이를 &lt;code&gt;rbash&lt;/code&gt;라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1689127887226&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;The Restricted Shell (Bash Reference Manual)&quot; data-og-description=&quot;6.10 The Restricted Shell If Bash is started with the name rbash, or the --restricted or -r option is supplied at invocation, the shell becomes restricted. A restricted shell is used to set up an environment more controlled than the standard shell. A restr&quot; data-og-host=&quot;www.gnu.org&quot; data-og-source-url=&quot;https://www.gnu.org/software/bash/manual/html_node/The-Restricted-Shell.html&quot; data-og-url=&quot;https://www.gnu.org/software/bash/manual/html_node/The-Restricted-Shell.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/The-Restricted-Shell.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.gnu.org/software/bash/manual/html_node/The-Restricted-Shell.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;The Restricted Shell (Bash Reference Manual)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;6.10 The Restricted Shell If Bash is started with the name rbash, or the --restricted or -r option is supplied at invocation, the shell becomes restricted. A restricted shell is used to set up an environment more controlled than the standard shell. A restr&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.gnu.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;본 문서에서는 &lt;code&gt;rbash&lt;/code&gt;를 이용하여 사용자가 사용가능한 명령어를 제한하기 위한 방법을 설명한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;span&gt;1. Restricted Shell 생성&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;rbash&lt;/code&gt;를 생성하는 법은 아래와 같은 간단한 명령어로 가능하다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;cp /bin/bash /bin/rbash&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 &lt;code&gt;bash&lt;/code&gt; 자체가 &lt;code&gt;restricted mode&lt;/code&gt;를 지원하며, 바이너리 명을 &lt;code&gt;rbash&lt;/code&gt;로 두는것 만으로도 손쉽게 적용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;rbash&lt;/code&gt;에서 제한된 기능은 아래와 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;cd 명령(디렉토리 변경)&lt;/li&gt;
&lt;li&gt;PATH(설정/해제)&lt;/li&gt;
&lt;li&gt;ENV 일명 BASH_ENV(환경 설정/설정 해제)&lt;/li&gt;
&lt;li&gt;기능 가져오기&lt;/li&gt;
&lt;li&gt;인수 '/'를 포함하는 파일 이름 지정&lt;/li&gt;
&lt;li&gt;인수 '-'를 포함하는 파일 이름 지정&lt;/li&gt;
&lt;li&gt;'&lt;b&gt;&amp;gt;&lt;/b&gt;', '&lt;b&gt;&amp;gt;&amp;gt;&lt;/b&gt;', '&lt;b&gt;&amp;gt;|&lt;/b&gt;', '&lt;b&gt;&amp;lt;&amp;gt;&lt;/b&gt; 을 사용하여 출력 리디렉션 ', '&lt;b&gt;&amp;gt;&amp;amp;&lt;/b&gt;', '&lt;b&gt;&amp;amp;&amp;gt;&lt;/b&gt;'&lt;/li&gt;
&lt;li&gt;'&lt;b&gt;set +r&lt;/b&gt;' 또는 '&lt;b&gt;set +o&lt;/b&gt;'를 사용하여 제한 해제&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;span&gt;2. 유저 생성 및 rbash 적용&lt;/span&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;2.1. 신규유저&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신규 유저를 생성할 때, 기본적으로 적용될 &lt;code&gt;shell&lt;/code&gt;을 &lt;code&gt;-s&lt;/code&gt; 옵션을 주어 &lt;code&gt;rbash&lt;/code&gt;로 설정한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;useradd -s /bin/rbash ${USER}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;2.2. 기존 유저&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존 유저의 &lt;code&gt;shell&lt;/code&gt;을 &lt;code&gt;usermod&lt;/code&gt; 명령어의 &lt;code&gt;-s&lt;/code&gt; 옵션을 이용하여 변경한다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;usermod -s /bin/rbash ${USER}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;3. 명령어 제한&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;리눅스에서는 기본적으로 명령어 입력 시 쉘에서 기본적으로 제공하는 기능을 제외한 나머지 기능들은 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;code&gt;$PATH&lt;/code&gt;에 등록된 바이너리를 실행하는 방식으로 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한, 설치된 프로그램의 바이너리는 &lt;code&gt;/bin/&lt;/code&gt; &lt;code&gt;/usr/bin&lt;/code&gt; 등의 경로에 등록되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, &lt;code&gt;rbash&lt;/code&gt;를 사용할 때 &lt;code&gt;$PATH&lt;/code&gt; 가 바이너리가 설치된 경로가 아닌, 별도의 공간을 가리키게 하여 사용자의 명령어를 제한 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1. profile 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bash profile을 생성하여 해당 사용자가 실행가능한 바이너리 목록을 &lt;code&gt;user home&lt;/code&gt;에 지정하고 &lt;code&gt;$PATH&lt;/code&gt;에 등록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 해당 사용자가 임의로 &lt;code&gt;$PATH&lt;/code&gt;를 수정할 수 없도록 설정한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF &amp;gt; /home/${USER}/.bash_profile
readonly PATH=$HOME/programs #PATH 변경 못하도록 readonly 처리
export PATH 
EOF&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;.bashrc&lt;/code&gt; 파일의 내용을 제거한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF &amp;gt; /home/${USER}/.bashrc
EOF&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 임의로 파일을 수정할 수 없도록 권한을 변경한다&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;chown root.root /home/${USER}/* -R
chmod 755 /home/${USER}/* -R
chattr -i /home/${USER}/.bashrc
chattr -i /home/${USER}/.bash_profile&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 과정을 수행하면 &lt;code&gt;$PATH&lt;/code&gt;의 수정을 제한하게 되며, &lt;code&gt;rbash&lt;/code&gt;가 실행할 수 있는 프로그램의 목록은 &lt;code&gt;/home/${user}/programs&lt;/code&gt; 에 등록된 바이너리로 한정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;3.2 &lt;/span&gt;&lt;span&gt;프로그램 허용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 가능한 프로그램을 담을 디렉터리를 생성한다.&lt;/p&gt;
&lt;div data-language=&quot;bash&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;mkdir /home/${USER}/programs&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 디렉터리에 사용 허용할 프로그램을 등록한다.&lt;/p&gt;
&lt;pre id=&quot;code_1689128775899&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cp /bin/pwd /home/${user}/programs # 예시, pwd 사용 허가&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;rbash&lt;/code&gt;가 실행된 상태에서 &lt;code&gt;/bin&lt;/code&gt; 에 등록된 바이너리를 실행할 경우 아래와 같은 메시지가 발생한다.&lt;/p&gt;
&lt;pre id=&quot;code_1689128939261&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[seong889@localhost ~]$ /bin/pwd
bash: /bin/pwd: restricted: cannot specify `/' in command names&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;code&gt;cd&lt;/code&gt; 명령어로 지정된 경로를 벗어나려 하더라도, 아래와 같은 메시지가 표출된다.&lt;/p&gt;
&lt;pre id=&quot;code_1689128969076&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[seong889@localhost ~]$ cd /
bash: cd: restricted&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;rbash&lt;/code&gt; 사용할경우 쉽게 사용자의 접근 제어가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 여러 단점이 존재하는데, 아래 링크를 보면 다양한 escape 방법이 소개되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1689129055621&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;rbash escape | rbash restricted shell escape&quot; data-og-description=&quot;rbash escape | rbash restricted shell escape How to bypass rbash restricted shell. Today we are share many way to bypass rbash restricted shell&quot; data-og-host=&quot;www.hacknos.com&quot; data-og-source-url=&quot;https://www.hacknos.com/rbash-escape-rbash-restricted-shell-escape/&quot; data-og-url=&quot;https://www.hacknos.com/rbash-escape-rbash-restricted-shell-escape/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c0Tt11/hyTgO64kVh/IncxRO9ndq3gv15EBdomc1/img.png?width=595&amp;amp;height=290&amp;amp;face=0_0_595_290,https://scrap.kakaocdn.net/dn/bFVFPL/hyTitG1mZp/2a0ONXCpIaddDvgSoKF7m1/img.png?width=990&amp;amp;height=793&amp;amp;face=0_0_990_793,https://scrap.kakaocdn.net/dn/cbJf0y/hyTiwwYlQ2/Pi548CZgXYDBY9SkjAkhN0/img.png?width=925&amp;amp;height=423&amp;amp;face=0_0_925_423&quot;&gt;&lt;a href=&quot;https://www.hacknos.com/rbash-escape-rbash-restricted-shell-escape/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.hacknos.com/rbash-escape-rbash-restricted-shell-escape/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c0Tt11/hyTgO64kVh/IncxRO9ndq3gv15EBdomc1/img.png?width=595&amp;amp;height=290&amp;amp;face=0_0_595_290,https://scrap.kakaocdn.net/dn/bFVFPL/hyTitG1mZp/2a0ONXCpIaddDvgSoKF7m1/img.png?width=990&amp;amp;height=793&amp;amp;face=0_0_990_793,https://scrap.kakaocdn.net/dn/cbJf0y/hyTiwwYlQ2/Pi548CZgXYDBY9SkjAkhN0/img.png?width=925&amp;amp;height=423&amp;amp;face=0_0_925_423');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;rbash escape | rbash restricted shell escape&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;rbash escape | rbash restricted shell escape How to bypass rbash restricted shell. Today we are share many way to bypass rbash restricted shell&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.hacknos.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 &lt;code&gt;rbash&lt;/code&gt; 자체에서 &lt;code&gt;/경로/바이너리&lt;/code&gt; 방식으로 프로그램에 접근하는 것을 막는 것이기 때문에, shell과 관련이 있는 프로그램에 의해 &lt;code&gt;rbash&lt;/code&gt;를 벗어 날 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 파일에 대한 접근 자체를 차단할 수 없다&lt;/p&gt;
&lt;pre id=&quot;code_1689129166319&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ls /&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 명령어를 입력해도 전체적인 파일의 목록이 노출되는데, 이는 sftp 로 접근했을 때도 파일 목록이 노출되게 되며심지어 파일 다운로드도 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 막기 위해선 접근을 막을 경로에 대해 퍼미션 제한을 세심하게 걸어줄 필요가 존재한다.&lt;/p&gt;
&lt;pre id=&quot;code_1689129229111&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chmod 550 / # 동작 테스트를 해보지는 못했다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1. 대안&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 명령어 제한을 위해 각 서버의 디렉터리들을 모두 조사하고, 퍼미션을 설정하는것은 엄청난 노동이다. 또한, 실수로 설정하지 못한 경로가 존재할 경우 사용자가 마음대로 접근 가능 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 문제로는 일부 서비스(ex. apache)의 경우 자체적인 권한을 갖고 동작 하기 때문에 문제가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;root.root&lt;/code&gt; 권한으로 &lt;code&gt;550(r-x r-x ---)&lt;/code&gt;으로 설정하게 될 경우, 일부 서비스가 구동에 필요한 디렉터리에 접근하지 못해 서비스가 동작하지 않는 문제가 발생할 수 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서, 이에 대한 대안으로 &lt;code&gt;container&lt;/code&gt; 기능을 사용하여 &lt;code&gt;sshd&lt;/code&gt; 및 사용자에 필요한 프로그램만 설치하고, 사용자가 접근해야 할 파일들에 한해 볼륨 마운트 하여 제공하는 방법을 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에대한 방법은 추후 작성할 예정이다.&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <category>Linux</category>
      <category>rbash</category>
      <category>사용자제어</category>
      <category>접근제어</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/68</guid>
      <comments>https://stackov.tistory.com/68#entry68comment</comments>
      <pubDate>Wed, 12 Jul 2023 11:49:51 +0900</pubDate>
    </item>
    <item>
      <title>[javascript] for...in 사용시 주의사항 (with prototype)</title>
      <link>https://stackov.tistory.com/67</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 내에서 공통으로 사용하기 위해서 prototype에 확장함수를 등록하여 사용하던 중 문제가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확장함수를 포함하여 개발된 라이브러리를 html에서 import하고 페이지를 로드하니 정상적으로 동작하던 기능들이 정상동작하지 않는 문제가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 &lt;code&gt;Array.prototype.forEach&lt;/code&gt; 또는 &lt;code&gt;Array.prototype.map&lt;/code&gt;을 사용하여 배열의 요소들을 다뤘는데, 공동으로 작업하다 보니 &lt;code&gt;for (let i in array)&lt;/code&gt;와 같은 방법으로 처리한 코드가 존재했기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제가 발생한 사항은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;if(!Array.prototype.hasOwnProperty('fname')) {
    Array.prototype.fname = function(){} 
}

for (let i in [1, 2, 3]) {
    console.log(i)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 코드를 입력하면 다음과 같은 결과를 예상할 것이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1
2
3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실제 결과는 다음과 같았다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1
2
3
fname&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 이런 일이 발생했는가 하니, &lt;code&gt;for...in&lt;/code&gt; 문법은 object의 모든 property를 대상으로 순회를 하는데, &lt;code&gt;Array.prototype.A = ...&lt;/code&gt; 식으로 공통 함수를 등록하게 될 경우에도 property 취급을 하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1689123263316&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;for...in - JavaScript | MDN&quot; data-og-description=&quot;for...in문은 상속된 열거 가능한 속성들을 포함하여 객체에서 문자열로 키가 지정된 모든 열거 가능한 속성에 대해 반복합니다. (Symbol로 키가 지정된 속성은 무시합니다.)&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/for...in&quot; data-og-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/for...in&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/da9Xu8/hyTiw4LhUC/po6Q2YyAr43YrewwWgBivK/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/for...in&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/for...in&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/da9Xu8/hyTiw4LhUC/po6Q2YyAr43YrewwWgBivK/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;for...in - JavaScript | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;for...in문은 상속된 열거 가능한 속성들을 포함하여 객체에서 문자열로 키가 지정된 모든 열거 가능한 속성에 대해 반복합니다. (Symbol로 키가 지정된 속성은 무시합니다.)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;위의 개발문서에서 발견한 추가적인 문제 중 하나는 for...in 을 사용하게 될 경우 Array 내 index 순서 보장 되지 않아 개발자가 의도한 결과와 다른 결과가 도출될 수 있다고 한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해 조치한 코드는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;if(!Array.prototype.hasOwnProperty('fname')) {
    Object.defineProperty(Array.prototype, &quot;fname&quot;, {
        enumerable: false,
        value: function() {}
    })
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 prototype에 property를 정의하면 더이상 &lt;code&gt;for...in&lt;/code&gt; 에서 임의로 정의한 확장함수가 노출되는 경우는 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, Array의 순회를 위해선 &lt;code&gt;for...in&lt;/code&gt; 대신 &lt;code&gt;Array.prototype.forEach&lt;/code&gt; 또는 &lt;code&gt;Array.prototype.map&lt;/code&gt; 를 사용할 수 있도록 주의를 주어야 할 것 같다.&lt;/p&gt;</description>
      <category>Programming</category>
      <category>Array</category>
      <category>for...in</category>
      <category>javascript</category>
      <category>Prototype</category>
      <category>확장함수</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/67</guid>
      <comments>https://stackov.tistory.com/67#entry67comment</comments>
      <pubDate>Wed, 12 Jul 2023 00:16:23 +0900</pubDate>
    </item>
    <item>
      <title>[NodeJS] Cannot read property 'Symbol(requestOptions)' of undefined</title>
      <link>https://stackov.tistory.com/66</link>
      <description>&lt;p&gt;서비스 배포를 준비하기 위해 개발서버 상에서 테스트를 수행하던 중 개발PC에선 보지 못한 오류를 발견했다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_http_agent.js:444
      options = req[kRequestOptions];
                   ^

TypeError: Cannot read property &amp;#39;Symbol(requestOptions)&amp;#39; of undefined
    at Agent.removeSocket (_http_agent.js:444:20)
    at TLSSocket.onClose (_http_agent.js:371:11)
    at TLSSocket.emit (events.js:327:22)
    at net.js:673:12
    at TCP.done (_tls_wrap.js:563:7)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;원인을 다양한 방법으로 찾아보았으나, 원인을 파악하기 쉽지 않았다.&lt;/p&gt;
&lt;p&gt;express의 res에서 데이터를 전달하는 방법을 &lt;code&gt;res.send()&lt;/code&gt; 에서 &lt;code&gt;res.write()&lt;/code&gt;로 바꿔 보는 등의 조치를 취했으나 전혀 오류가 해결되지 않았다.&lt;/p&gt;
&lt;p&gt;방법은 어이없게 해결되었다.&lt;/p&gt;
&lt;p&gt;NodeJS 13 ~ 14 버전 상에서 &lt;code&gt;Object.prototype&lt;/code&gt;을 변경할 경우, 해당 문제가 발생 할 수 있다는 것이었다.&lt;/p&gt;
&lt;p&gt;내 경우, Object에서 null인 항목을 모두 제거하는 동작의 처리를 위해 &lt;code&gt;Object.prototype.removeNull&lt;/code&gt; 함수를 정의했는데,&lt;br&gt;이를 &lt;code&gt;function removeNull(obj)&lt;/code&gt;로 변경하여 처리하였더니 더이상 해당 오류가 발생하지 않았다.&lt;/p&gt;</description>
      <category>Programming/JS</category>
      <category>http agent</category>
      <category>nodejs</category>
      <category>options = req[kRequestOptions];</category>
      <category>TypeError: Cannot read property 'Symbol(requestOptions)' of undefined</category>
      <category>_http_agent.js:444</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/66</guid>
      <comments>https://stackov.tistory.com/66#entry66comment</comments>
      <pubDate>Tue, 27 Sep 2022 17:47:29 +0900</pubDate>
    </item>
    <item>
      <title>[gitlab] Create Merge Request 시 기본 branch명 변경</title>
      <link>https://stackov.tistory.com/65</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로, gitlab의 issue에서 merge request를 생성할 때, 브랜치 명은 다음 규칙을 따른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;{이슈번호}-{이슈명 축약}&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이슈명의 경우, 한글로 작성할 경우 &lt;code&gt;{이슈번호}-&lt;/code&gt; 로만 표기되는 경우도 잦고, 이슈만을 위한 branch를 찾기도 번거롭다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, branch명의 템플릿을 변경하는 방법에 대해 작성하고자 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Merge Request branch name template 변경&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;embedded/service/gitlab-rails/app/models/issue.rb&lt;/code&gt; 파일의 &lt;code&gt;to_branch_name&lt;/code&gt; 함수 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변경전&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;  def to_branch_name
    if self.confidential?
      &quot;#{iid}-confidential-issue&quot;
    else
      self.class.to_branch_name(iid, title)
    end
  end&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변경후&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;  def to_branch_name
    if self.confidential?
      &quot;#{iid}-confidential-issue&quot;
    else
      #self.class.to_branch_name(iid, title)
      &quot;issue/#{iid}&quot;
    end
  end&lt;/code&gt;&lt;/pre&gt;
&lt;details&gt;
&lt;summary&gt;이전버전&lt;/summary&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변경전&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;  def to_branch_name
    if self.confidential?
      &quot;#{iid}-confidential-issue&quot;
    else
      branch_name = &quot;#{iid}-#{title.parameterize}&quot; # 변경지점

      if branch_name.length &amp;gt; 100
        truncated_string = branch_name[0, 100]
        # Delete everything dangling after the last hyphen so as not to risk
        # existence of unintended words in the branch name due to mid-word split.
        branch_name = truncated_string[0, truncated_string.rindex(&quot;-&quot;)]
      end

      branch_name
    end
  end&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변경후&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;  def to_branch_name
    if self.confidential?
      &quot;#{iid}-confidential-issue&quot;
    else
      branch_name = &quot;issue/#{iid}&quot;

      if branch_name.length &amp;gt; 100
        truncated_string = branch_name[0, 100]
        # Delete everything dangling after the last hyphen so as not to risk
        # existence of unintended words in the branch name due to mid-word split.
        branch_name = truncated_string[0, truncated_string.rindex(&quot;-&quot;)]
      end

      branch_name
    end
  end&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;변경 결과&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경 및 gitlab 서버를 재기동 후에 &lt;code&gt;Create merge request&lt;/code&gt;의 drop down 메뉴를 열어보면 설정된 값으로 변환되어 있음을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;305&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyqzRZ/btrCmd3OQrN/de3brYp3agrIKdcEp4YXnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyqzRZ/btrCmd3OQrN/de3brYp3agrIKdcEp4YXnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyqzRZ/btrCmd3OQrN/de3brYp3agrIKdcEp4YXnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyqzRZ%2FbtrCmd3OQrN%2Fde3brYp3agrIKdcEp4YXnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;305&quot; height=&quot;411&quot; data-origin-width=&quot;305&quot; data-origin-height=&quot;411&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기타 변수들을 잘 활용할 경우 &lt;code&gt;issue/{이슈번호}&lt;/code&gt; 템플릿 외의 다른 템플릿을 적용하여 사용할 수 있을것으로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gitlab을 업데이트 할 경우, 해당 변경 사항이 원상복귀 될 것으로 보이는데, 해당 부분은 차기 버전에서 설정으로 변경 가능하도록 적용해줬으면 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2023.07.20 - 추가&lt;/h3&gt;
&lt;figure id=&quot;og_1689854393428&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Configure branch name for creating MR from an issue (!93108) &amp;middot; Merge requests &amp;middot; GitLab.org / GitLab &amp;middot; GitLab&quot; data-og-description=&quot;What does this MR do and why? A user can create a branch from an issue:&quot; data-og-host=&quot;gitlab.com&quot; data-og-source-url=&quot;https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93108&quot; data-og-url=&quot;https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93108&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cTGqt1/hyTnRVshL8/MN2SNFj9aLs0N4Beqh3OYK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/rBPQY/hyTnHywTzZ/sn4MzDv7saKU0tWZ2i1jP0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93108&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93108&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cTGqt1/hyTnRVshL8/MN2SNFj9aLs0N4Beqh3OYK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/rBPQY/hyTnHywTzZ/sn4MzDv7saKU0tWZ2i1jP0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Configure branch name for creating MR from an issue (!93108) &amp;middot; Merge requests &amp;middot; GitLab.org / GitLab &amp;middot; GitLab&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;What does this MR do and why? A user can create a branch from an issue:&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gitlab.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언제인지 모를 시점에 각 Repository의 branch name을 설정할 수 있는 기능이 GitLab에 merge 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-pm-slice=&quot;0 0 []&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1618&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7oQG7/btsopBWtDBM/M6x0qHy3cvwoZXTLNiYOh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7oQG7/btsopBWtDBM/M6x0qHy3cvwoZXTLNiYOh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7oQG7/btsopBWtDBM/M6x0qHy3cvwoZXTLNiYOh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7oQG7%2FbtsopBWtDBM%2FM6x0qHy3cvwoZXTLNiYOh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1618&quot; height=&quot;458&quot; data-origin-width=&quot;1618&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Settings &amp;gt; Repository&lt;/code&gt;의 &lt;code&gt;branch defaults&lt;/code&gt; 항목에 위에 첨부된 이미지와 같은 설정이 추가되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;issue/%{id} 와 같은 방법으로 설정하면, template가 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;code&gt;issue.rb&lt;/code&gt; 에서 &lt;code&gt;to_branch_name&lt;/code&gt;을 조작하였다면, 내부에서 Template 적용 로직이 수행되지 않아 branch name 설정 기능이 동작하지 않는다.&lt;br /&gt;현재는, Admin Area 또는 Group 에서 전역적인 설정을 할 수 없고 각 Repository에서 개별 설정을 해야 한다.&lt;/blockquote&gt;</description>
      <category>Code/git</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/65</guid>
      <comments>https://stackov.tistory.com/65#entry65comment</comments>
      <pubDate>Tue, 17 May 2022 14:56:25 +0900</pubDate>
    </item>
    <item>
      <title>[QT] Windows에서 QOCI (Oricle DB) Driver 빌드</title>
      <link>https://stackov.tistory.com/64</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.rixa.kr/60&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Programming/QT] - [QT] CentOS 7 환경에서 QOCI (Oracle DB) Driver 빌드&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1631239268349&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[QT] CentOS 7 환경에서 QOCI (Oracle DB) Driver 빌드&quot; data-og-description=&quot;필수 환경 QT 설치 QT 공식홈페이지 에서 QT를 다운로드 받아 설치한다. 설치 과정 중 필수로 Source 를 선택하여 QT소스코드가 함께 설치되도록한다. 본 게시글에서는 QT 5.9.1 버전을 사용한다. 설치 &quot; data-og-host=&quot;blog.rixa.kr&quot; data-og-source-url=&quot;https://blog.rixa.kr/60&quot; data-og-url=&quot;https://blog.rixa.kr/60&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gOKHf/hyLxFb0jjL/NyL4kmJCYRzu3Phd5lAUZ1/img.png?width=800&amp;amp;height=378&amp;amp;face=0_0_800_378,https://scrap.kakaocdn.net/dn/e8BgH/hyLyQCX7Tb/nsmx4r3EWu4CkX5kl4XkmK/img.png?width=800&amp;amp;height=378&amp;amp;face=0_0_800_378,https://scrap.kakaocdn.net/dn/4pzMC/hyLxKxy0K8/WN0StoGHJFTUFbtXxte1mk/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://blog.rixa.kr/60&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.rixa.kr/60&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gOKHf/hyLxFb0jjL/NyL4kmJCYRzu3Phd5lAUZ1/img.png?width=800&amp;amp;height=378&amp;amp;face=0_0_800_378,https://scrap.kakaocdn.net/dn/e8BgH/hyLyQCX7Tb/nsmx4r3EWu4CkX5kl4XkmK/img.png?width=800&amp;amp;height=378&amp;amp;face=0_0_800_378,https://scrap.kakaocdn.net/dn/4pzMC/hyLxKxy0K8/WN0StoGHJFTUFbtXxte1mk/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[QT] CentOS 7 환경에서 QOCI (Oracle DB) Driver 빌드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;필수 환경 QT 설치 QT 공식홈페이지 에서 QT를 다운로드 받아 설치한다. 설치 과정 중 필수로 Source 를 선택하여 QT소스코드가 함께 설치되도록한다. 본 게시글에서는 QT 5.9.1 버전을 사용한다. 설치&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.rixa.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스팅에서는, QOCI 드라이버의 빌드를 CentOS 7 환경에서 진행하는 것으로 작성하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 Windows에서 QOCI 빌드를 하는 법을 설명하려 한다.&lt;/p&gt;
&lt;h1&gt;필수 환경&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;QT 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;QT 공식홈페이지 에서 QT를 다운로드 받아 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 과정 중 필수로 Source 를 선택하여 QT소스코드가 함께 설치되도록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 게시글에서는 QT 5.9.1 버전을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 환경으로는 MinGW 32bit를 사용하고있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;158&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JN9fX/btreBkEQx5r/Ky1X8WIPInqOvNISA921iK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JN9fX/btreBkEQx5r/Ky1X8WIPInqOvNISA921iK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JN9fX/btreBkEQx5r/Ky1X8WIPInqOvNISA921iK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJN9fX%2FbtreBkEQx5r%2FKy1X8WIPInqOvNISA921iK%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;158&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Oracle SDK&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle Instant Client 에서 Oracle Instant Client를 다운받는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Basic Package (ZIP)&lt;/li&gt;
&lt;li&gt;SDK Package (ZIP)&lt;br /&gt;본 게시글에서는 19.12 버전(x86)을 사용하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;' Windows가 64bit를 사용하고 있더라도, Qt 설치시 MinGW를 32bit용으로 설치하였을 경우, 32bit용 라이브러리르 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 파일의 압축 해제는 &quot;D:\tmp\instant-client&quot; 에 했다.&lt;/p&gt;
&lt;h1&gt;빌드&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;sqldriver&lt;/code&gt;의 소스코드가 위치한 경로로 이동한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;QT설치경로\5.9.1\Src\qtbase\src\plugins\sqldrivers\plugins\sqldrivers&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 경로에 대해 CMd창을 실행한 뒤 아래 명령어를 입력한다.&lt;/p&gt;
&lt;pre class=&quot;taggerscript&quot;&gt;&lt;code&gt;qmake -- OCI_INCDIR=&quot;D:\tmp\instant-client\instantclient_19_12_x86\sdk\include&quot; OCI_LIBDIR=&quot;D:\tmp\instant-client\instantclient_19_12_x86\sdk\lib\msvc&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 경로는 본인의 환경에 따라 적절히 수정해주면 되며, &lt;code&gt;OCI_INCDIR&lt;/code&gt;은 instant-client의 include 경로를, &lt;code&gt;OCI_LIBDIR&lt;/code&gt;은 instant-client의 &lt;code&gt;oci.lib&lt;/code&gt; 파일이 위치한 경로를 입력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 명령어를 입력하면 아래와 같은 내용이 표출된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Running configuration tests...
Checking for DB2 (IBM)... no
Checking for InterBase... no
Checking for MySQL... no
Checking for OCI (Oracle)... yes
Checking for ODBC... yes
Checking for PostgreSQL... no
Checking for SQLite (version 2)... no
Checking for TDS (Sybase)... no
Done running configuration tests.

Configure summary:

Qt Sql:
  DB2 (IBM) .............................. no
  InterBase .............................. no
  MySql .................................. no
  OCI (Oracle) ........................... yes
  ODBC ................................... yes
  PostgreSQL ............................. no
  SQLite2 ................................ no
  SQLite ................................. yes
    Using system provided SQLite ......... no
  TDS (Sybase) ........................... no&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 부분은 신경쓰지 않아도 되고, OCI (Oracle)이 &quot;yes&quot; 인 것만 확인하면 되며, &quot;no&quot;가 뜰 경우 경로를 다시 확인하고, &lt;code&gt;config.cache&lt;/code&gt; 파일을 삭제한 뒤 다시 명령어를 입력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 과정까지 완료되었을 경우, mingw32-make 명령어를 실행해 컴파일을 실행한다.&lt;/p&gt;
&lt;h1&gt;결과물&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 실행 결과물로, &lt;code&gt;plugins\sqldrivers\qsqloci.dll&lt;/code&gt; 및 &lt;code&gt;plugins\sqldrivers\qsqlocid.dll&lt;/code&gt;이 생성되면 컴파일에 성공하였다.&lt;/p&gt;</description>
      <category>Programming/QT</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/64</guid>
      <comments>https://stackov.tistory.com/64#entry64comment</comments>
      <pubDate>Fri, 10 Sep 2021 11:00:18 +0900</pubDate>
    </item>
    <item>
      <title>[QT] QOCI를 이용한 CLOB 데이터 insert중 ORA-03113 (EOF) 오류 발생 대처법</title>
      <link>https://stackov.tistory.com/63</link>
      <description>&lt;h1&gt;오류 발생&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴 길이의 QString 데이터를 CLOB column에 insert 하자, &lt;code&gt;ORA-03113 &quot;end of file on communication channel&quot;&lt;/code&gt; 오류가 발생하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1625038959858&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Master Note: Troubleshooting ORA-03113&quot; data-og-description=&quot;Master Note: Troubleshooting ORA-03113 (Doc ID 1506805.1) Last updated on MARCH 12, 2021 Applies to: Oracle Database Exadata Express Cloud Service - Version N/A and later Oracle Database Cloud Service - Version N/A and later Oracle Database - Enterprise Ed&quot; data-og-host=&quot;support.oracle.com&quot; data-og-source-url=&quot;https://support.oracle.com/knowledge/Oracle%20Database%20Products/1506805_1.html&quot; data-og-url=&quot;https://support.oracle.com/knowledge/Oracle%20Database%20Products/1506805_1.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://support.oracle.com/knowledge/Oracle%20Database%20Products/1506805_1.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://support.oracle.com/knowledge/Oracle%20Database%20Products/1506805_1.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Master Note: Troubleshooting ORA-03113&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Master Note: Troubleshooting ORA-03113 (Doc ID 1506805.1) Last updated on MARCH 12, 2021 Applies to: Oracle Database Exadata Express Cloud Service - Version N/A and later Oracle Database Cloud Service - Version N/A and later Oracle Database - Enterprise Ed&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;support.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h1&gt;원인 파악&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ORA-03113&lt;/code&gt;과 관련된 문서를 찾아보니, 현재 상황과 맞는 뚜렷한 원인을 파악하기 힘들었다.&lt;br /&gt;오류가 발생한 쿼리를 조사해 본 결과 CLOB column에 data insert를 하는 쿼리가 동작하는 부분이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 부분은 아래와 같이 &lt;code&gt;QSqlQuery&lt;/code&gt;를 통해 prepared statement를 통하여 string을 &lt;b&gt;CLOB Column&lt;/b&gt;에 insert(또는 update) 하는 로직이다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;QString text = &quot;blah~ blah~~~~ ....&quot;; // 긴 길이의 텍스트

QSqlQuery query(m_db);
query.prepare(&quot;insert into A(longdata) values(:longdata)&quot;);
query.bindValue(&quot;:longdata&quot;, QVariant(text));

query.exec();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 prepared statement를 정의하고, data를 bind한 뒤, 쿼리를 실행해본 결과 처음 몇개의 쿼리는 정상적으로 INSERT 되었으나, 어느순간부터 &lt;code&gt;ORA-03113&lt;/code&gt; 에러 발생 후 &lt;code&gt;ORA-03114(Not connected to Oracle)&lt;/code&gt; 메시지가 지속적으로 발생하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속적으로 디버깅 한 결과, String의 길이가 일정이상 늘어나게 되면 해당 부분에서 오류가 발생하는 것이다.&lt;/p&gt;
&lt;h1&gt;문제 해결&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시나 놓치고 있는 부분이 무엇인지 찾기위해 다음과 같은 행위를 수행했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Column의 Type 변경 (CLOB -&amp;gt; LONG)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 테이블에 하나의 LONG 컬럼만 정의 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Query 실행 로직 변경
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;뚜렷한 방안을 찾기 어려움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SQL 문에서 insert시 CLOB을 별도로 처리해야하는가?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(정답) to_clob을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 행위를 수행해본 결과, insert 시에 data를 clob형으로 변경하여 수행할 경우 문제 없이 데이터가 insert되는것을 확인하였다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;#이전 query
insert into A(longdata) values(:longdata)
#수정후 query
insert into A(longdata) values(to_clob(:longdata))&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;결론&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확한 해결 방안인지는 모르겠으나 insert 또는 update를 수행할 때 길이가 긴 string을 바로 bind해서 처리할 경우 EOF문제가 발생하며, 이를 해결하기 위해 &lt;code&gt;to_clob&lt;/code&gt;을 사용하여 형변환이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 CLOB 데이터를 사용하기 위해 별도로 코드를 변경할 필요가 없었다.&lt;/p&gt;</description>
      <category>Programming/QT</category>
      <category>03113</category>
      <category>CLOB</category>
      <category>ORA-03113</category>
      <category>oracle</category>
      <category>QOCI</category>
      <category>QT</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/63</guid>
      <comments>https://stackov.tistory.com/63#entry63comment</comments>
      <pubDate>Wed, 30 Jun 2021 16:40:06 +0900</pubDate>
    </item>
    <item>
      <title>[Oracle] Key 중복 시 insert 대신 update 처리 (merge into)</title>
      <link>https://stackov.tistory.com/62</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;테이블에서 중복값 방지를 위한 contraint가 걸려있을 경우, 중복 키값을 가진 row를 insert 하면 오류가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 일반적인 방법으로는 insert를 하기 전 중복된 키를 가진 값이 이미 table에 존재하는지를 파악하고, 이미 존재할 경우 update를 하도록 구현하여아 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 중복키 여부를 확인하기 위한 로직을 작성하지 않고도 쿼리 하나로 insert 또는 update를 수행하도록 설정할 수 있는 방법이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_9016.htm#SQLRF01606&quot;&gt;Oracle 공식 Document&lt;/a&gt; 를 참고하면, &lt;code&gt;INSERT ON DUPLICATE KEY UPDATE&lt;/code&gt; 구문을 통해 처리할 수 있음을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1625037317873&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MERGE&quot; data-og-description=&quot;Prerequisites You must have the INSERT and UPDATE object privileges on the target table and the SELECT object privilege on the source table. To specify the DELETE clause of the merge_update_clause, you must also have the DELETE object privilege on the targ&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_9016.htm#SQLRF01606&quot; data-og-url=&quot;https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_9016.htm#SQLRF01606&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_9016.htm#SQLRF01606&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_9016.htm#SQLRF01606&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MERGE&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Prerequisites You must have the INSERT and UPDATE object privileges on the target table and the SELECT object privilege on the source table. To specify the DELETE clause of the merge_update_clause, you must also have the DELETE object privilege on the targ&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Syntax&lt;/h2&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;MERGE INTO table_name
            USING (table | view | subquery) alias
                 ON (join condition)                                    
            WHEN MATCHED THEN
                     UPDATE SET col1 = val1[, ...]
            WHEN NOT MATCHED THEN
                     INSERT (column lists) VALUES (values);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 SQL은 &lt;code&gt;ID&lt;/code&gt;, &lt;code&gt;NAME&lt;/code&gt;, &lt;code&gt;BIRTH&lt;/code&gt; 세 column을 가지며, PK로 &lt;code&gt;ID&lt;/code&gt;설정된 테이블 &lt;code&gt;P&lt;/code&gt;가 있다고 가정할 때&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;MERGE INTO P
    USING dual
        ON (ID = 'AAA')
    WHEN NOT MATCHED THEN
        INSERT (ID, NAME, BIRTH)
        VALUES 'AAA', '홍길동', '2000-01-01')
    WHEN MATCHED THEN
        UPDATE SET
            NAME='홍길동',
            BIRTH='2000-01-01'           &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 쿼리를 작성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ID&lt;/code&gt;가 'AAA'인 데이터가 없을 경우 &lt;i&gt;(NOT MATCHED)&lt;/i&gt; INSERT를 통해 &lt;code&gt;ID&lt;/code&gt;가 &lt;i&gt;'AAA'&lt;/i&gt; 이며, &lt;code&gt;NAME&lt;/code&gt;이 &lt;i&gt;'홍길동'&lt;/i&gt;, &lt;code&gt;BIRTH&lt;/code&gt;가 &lt;i&gt;'2000-01-01'&lt;/i&gt; 인 데이터가 삽입된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 이미 'AAA'인 데이터가 존재할 경우 &lt;i&gt;(MATCHED)&lt;/i&gt;, UPDATE를 통해 &lt;code&gt;NAME&lt;/code&gt;을 &lt;i&gt;'홍길동'&lt;/i&gt;, &lt;code&gt;BIRTH&lt;/code&gt;를 _'2000-01-01'_로 설정하며, 이외의 값은 유지한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;타 DBMS&lt;/h2&gt;
&lt;figure id=&quot;og_1625037351400&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[MariaDB] Key 중복 시 insert 대신 update 처리 (INSERT ON DUPLICATE KEY UPDATE)&quot; data-og-description=&quot;테이블에서 중복값 방지를 위한 contraint가 걸려있을 경우, 중복 키값을 가진 row를 insert 하면 오류가 발생한다. 따라서 일반적인 방법으로는 insert를 하기 전 중복된 키를 가진 값이 이미 table에 존&quot; data-og-host=&quot;blog.rixa.kr&quot; data-og-source-url=&quot;https://blog.rixa.kr/61&quot; data-og-url=&quot;https://blog.rixa.kr/61&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/conF1M/hyKI80gHo6/UPKegQGG5IaNcRtd8QuibK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gLmf9/hyKI2Th7Lh/zzpG7FoJSeMhZHRjLwLaK0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cqqMNu/hyKKMgX7IY/wkXRGXOhzx41I7ly8GeU8K/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://blog.rixa.kr/61&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.rixa.kr/61&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/conF1M/hyKI80gHo6/UPKegQGG5IaNcRtd8QuibK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gLmf9/hyKI2Th7Lh/zzpG7FoJSeMhZHRjLwLaK0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cqqMNu/hyKKMgX7IY/wkXRGXOhzx41I7ly8GeU8K/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[MariaDB] Key 중복 시 insert 대신 update 처리 (INSERT ON DUPLICATE KEY UPDATE)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;테이블에서 중복값 방지를 위한 contraint가 걸려있을 경우, 중복 키값을 가진 row를 insert 하면 오류가 발생한다. 따라서 일반적인 방법으로는 insert를 하기 전 중복된 키를 가진 값이 이미 table에 존&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.rixa.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB</category>
      <category>db</category>
      <category>Insert</category>
      <category>oracle</category>
      <category>replace</category>
      <category>Update</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/62</guid>
      <comments>https://stackov.tistory.com/62#entry62comment</comments>
      <pubDate>Wed, 30 Jun 2021 16:11:00 +0900</pubDate>
    </item>
    <item>
      <title>[MariaDB] Key 중복 시 insert 대신 update 처리 (INSERT ON DUPLICATE KEY UPDATE)</title>
      <link>https://stackov.tistory.com/61</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;테이블에서 중복값 방지를 위한 contraint가 걸려있을 경우, 중복 키값을 가진 row를 insert 하면 오류가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 일반적인 방법으로는 insert를 하기 전 중복된 키를 가진 값이 이미 table에 존재하는지를 파악하고, 이미 존재할 경우 update를 하도록 구현하여아 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 중복키 여부를 확인하기 위한 로직을 작성하지 않고도 쿼리 하나로 insert 또는 update를 수행하도록 설정할 수 있는 방법이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mariadb.com/kb/en/insert-on-duplicate-key-update/&quot;&gt;MariaDB 공식 Document&lt;/a&gt; 를 참고하면, &lt;code&gt;INSERT ON DUPLICATE KEY UPDATE&lt;/code&gt; 구문을 통해 처리할 수 있음을 확인할 수 있다.&lt;/p&gt;
&lt;figure id=&quot;og_1625036585885&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;INSERT ON DUPLICATE KEY UPDATE&quot; data-og-description=&quot;INSERT if no duplicate key is found, otherwise UPDATE&quot; data-og-host=&quot;mariadb.com&quot; data-og-source-url=&quot;https://mariadb.com/kb/en/insert-on-duplicate-key-update/&quot; data-og-url=&quot;https://mariadb.com/kb/en/insert-on-duplicate-key-update/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://mariadb.com/kb/en/insert-on-duplicate-key-update/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mariadb.com/kb/en/insert-on-duplicate-key-update/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;INSERT ON DUPLICATE KEY UPDATE&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;INSERT if no duplicate key is found, otherwise UPDATE&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mariadb.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Syntax&lt;/h2&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
  [INTO] tbl_name [PARTITION (partition_list)] [(col,...)]
  {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
  [ ON DUPLICATE KEY UPDATE
    col=expr
      [, col=expr] ... ]&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 SQL은 &lt;code&gt;ID&lt;/code&gt;, &lt;code&gt;NAME&lt;/code&gt;, &lt;code&gt;BIRTH&lt;/code&gt; 세 column을 가지며, PK로 &lt;code&gt;ID&lt;/code&gt;설정된 테이블 &lt;code&gt;P&lt;/code&gt;가 있다고 가정할 때&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;INSERT INTO P(ID, NAME, BIRTH) values('AAA', '홍길동', '2000-01-01')
ON DUPLICATE KEY UPDATE
    NAME='홍길동',
    BIRTH='2000-01-01'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 쿼리를 작성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ID&lt;/code&gt;가 'AAA'인 데이터가 없을 경우 INSERT를 통해 &lt;code&gt;ID&lt;/code&gt;가 &lt;i&gt;'AAA'&lt;/i&gt; 이며, &lt;code&gt;NAME&lt;/code&gt;이 &lt;i&gt;'홍길동'&lt;/i&gt;, &lt;code&gt;BIRTH&lt;/code&gt;가 &lt;i&gt;'2000-01-01'&lt;/i&gt; 인 데이터가 삽입된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 이미 'AAA'인 데이터가 존재할 경우, UPDATE를 통해 &lt;code&gt;NAME&lt;/code&gt;을 &lt;i&gt;'홍길동'&lt;/i&gt;, &lt;code&gt;BIRTH&lt;/code&gt;를 &lt;i&gt;'2000-01-01'&lt;/i&gt;로 설정하며, 이외의 값은 유지한다.&lt;/p&gt;</description>
      <category>DB</category>
      <category>INSERT INTO ON DUPLICATE UPDATE</category>
      <category>mariaDB</category>
      <category>SQL</category>
      <category>중복삽입</category>
      <category>쿼리</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/61</guid>
      <comments>https://stackov.tistory.com/61#entry61comment</comments>
      <pubDate>Wed, 30 Jun 2021 14:05:46 +0900</pubDate>
    </item>
    <item>
      <title>[QT] CentOS 7 환경에서 QOCI (Oracle DB) Driver 빌드</title>
      <link>https://stackov.tistory.com/60</link>
      <description>&lt;h1&gt;필수 환경&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;QT 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.qt.io&quot;&gt;QT 공식홈페이지&lt;/a&gt; 에서 QT를 다운로드 받아 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 과정 중 필수로 Source 를 선택하여 QT소스코드가 함께 설치되도록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 게시글에서는 QT &lt;code&gt;5.9.1&lt;/code&gt; 버전을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 경로는 &lt;code&gt;/opt/Qt5.9.1&lt;/code&gt; 이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Oracle SDK&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.oracle.com/kr/database/technologies/instant-client/linux-x86-64-downloads.html&quot;&gt;Oracle Instant Client&lt;/a&gt; 에서 Oracle Instant Client를 다운받는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Basic Package (ZIP)&lt;/li&gt;
&lt;li&gt;SDK Package (ZIP)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 게시글에서는 &lt;code&gt;21.1.0.0.0&lt;/code&gt; 버전을 사용하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Basic Package&lt;/b&gt;는 &lt;code&gt;/opt/instantclient&lt;/code&gt;, &lt;b&gt;SDK Package&lt;/b&gt; 는 &lt;code&gt;opt/instantclient/sdk&lt;/code&gt; 에 압축 해제 하였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;빌드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCI의 소스코드가 위치한 경로로 이동한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;cd /opt/Qt5.9.1/5.9.1/Src/qtbase/src/plugins/sqldrivers/oci&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이동 후, &lt;code&gt;oci.pro&lt;/code&gt; 파일의 내용을 수정한다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;TARGET = qsqloci

HEADERS += $$PWD/qsql_oci_p.h
SOURCES += $$PWD/qsql_oci.cpp $$PWD/main.cpp


#QMAKE_USE += oci

darwin:QMAKE_LFLAGS += -Wl,-flat_namespace,-U,_environ

OTHER_FILES += oci.json

PLUGIN_CLASS_NAME = QOCIDriverPlugin

CONFIG += c++11
INCLUDEPATH += /opt/instantclient/sdk/include
DEPENDPATH += /opt/instantclient/
LIBS += -L&quot;/opt/instantclient&quot; -lclntsh


include(../qsqldriverbase.pri)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MakeFile&lt;/b&gt;을 생성한다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;qmake&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CentOS 7의 기본 GCC 버전이 4.8이므로, 바로 빌드 시 &lt;code&gt;-Wdate-time&lt;/code&gt; 및 &lt;code&gt;c++1z&lt;/code&gt; 오류가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;g++: error: unrecognized command line option '-std=c++1z'
g++: error: unrecognized command line option '-Wdate-time'&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, &lt;b&gt;MakeFile&lt;/b&gt; 의 내용을 수정한다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;c++1z&lt;/code&gt; -&amp;gt; &lt;code&gt;c++11&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-Wdate-time&lt;/code&gt; -&amp;gt; `` (제거)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후, 빌드를 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;make&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 로그가 콘솔에 출력되며, 빌드 성공 시 &lt;code&gt;../plguins/sqldrivers/&lt;/code&gt;(&lt;code&gt;/opt/Qt5.9.1/5.9.1/Src/qtbase/src/plugins/sqldrivers/plugins/sqldrivers&lt;/code&gt;) 폴더에 &lt;code&gt;libqsqloci.so&lt;/code&gt; 파일이 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 &lt;code&gt;libqsqloci.so&lt;/code&gt; 파일을 추가한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;cd /opt/Qt5.9.1/5.9.1/Src/qtbase/src/plugins/sqldrivers/plugins/sqldrivers
cp libqsqloci.so /opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCI의 설치가 완료되면, 테스트용 프로젝트를 생성하여 빌드 후 테스트를 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로젝트 파일&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/c8xd0a/btq8dy4iWbN/dkDn3i6fGTsoWkei4E6LXk/oratest.tar.gz?attach=1&amp;amp;knm=tfile.gz&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;oratest.tar.gz&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;503 B&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;test.cpp*&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;#include &amp;lt;QtSql&amp;gt;

int main() {
    QSqlDatabase mes_db;
        mes_db = QSqlDatabase::addDatabase(&quot;QOCI&quot;,&quot;TEST&quot;);
        mes_db .setHostName(&quot;localhost&quot;);
        mes_db .setPort(1521);
        mes_db .setUserName(&quot;test&quot;);
        mes_db .setPassword(&quot;test&quot;);
        mes_db .setDatabaseName(&quot;orcl&quot;);
        if(!mes_db .open()){
            qDebug()&amp;lt;&amp;lt;&quot;open false&quot;;
        }else {
            qDebug()&amp;lt;&amp;lt;&quot;open db&quot;;
        }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첨부된 압축파일의 압축 해제 후, test.cpp에서, oracle의 접속정보를 현재 설정된 상태와 맞게 변경 한 뒤, 빌드 및 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;open db&lt;/code&gt; 가 출력되면, 정상적으로 작업이 완료되었음을 의미하며, &lt;code&gt;open false&lt;/code&gt; 출력 시 접속 정보가 잘못되었음을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Plugin이 잘 로드되었는지 확인하기 위해선, 아래 사진과 같이 Run Environment에 &lt;code&gt;QT_DEBUG_PLUGINS&lt;/code&gt; 를 1로 설정한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;1218&quot; data-origin-height=&quot;576&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqONPU/btq8hqdnfKj/xY2fOknsjatOdwqEkp2at0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqONPU/btq8hqdnfKj/xY2fOknsjatOdwqEkp2at0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqONPU/btq8hqdnfKj/xY2fOknsjatOdwqEkp2at0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqONPU%2Fbtq8hqdnfKj%2FxY2fOknsjatOdwqEkp2at0%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;1218&quot; data-origin-height=&quot;576&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실행결과&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;QFactoryLoader::QFactoryLoader() checking directory path &quot;/usr/lib64/kde4/plugins/sqldrivers&quot; ...
QFactoryLoader::QFactoryLoader() checking directory path &quot;/usr/lib/kde4/plugins/sqldrivers&quot; ...
QFactoryLoader::QFactoryLoader() checking directory path &quot;/opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers&quot; ...
QFactoryLoader::QFactoryLoader() looking at &quot;/opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqlite.so&quot;
Found metadata in lib /opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqlite.so, metadata=
{
    &quot;IID&quot;: &quot;org.qt-project.Qt.QSqlDriverFactoryInterface&quot;,
    &quot;MetaData&quot;: {
        &quot;Keys&quot;: [
            &quot;QSQLITE&quot;
        ]
    },
    &quot;className&quot;: &quot;QSQLiteDriverPlugin&quot;,
    &quot;debug&quot;: false,
    &quot;version&quot;: 329985
}


Got keys from plugin meta data (&quot;QSQLITE&quot;)
QFactoryLoader::QFactoryLoader() looking at &quot;/opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqlmysql.so&quot;
Found metadata in lib /opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqlmysql.so, metadata=
{
    &quot;IID&quot;: &quot;org.qt-project.Qt.QSqlDriverFactoryInterface&quot;,
    &quot;MetaData&quot;: {
        &quot;Keys&quot;: [
            &quot;QMYSQL3&quot;,
            &quot;QMYSQL&quot;
        ]
    },
    &quot;className&quot;: &quot;QMYSQLDriverPlugin&quot;,
    &quot;debug&quot;: false,
    &quot;version&quot;: 329985
}


Got keys from plugin meta data (&quot;QMYSQL3&quot;, &quot;QMYSQL&quot;)
QFactoryLoader::QFactoryLoader() looking at &quot;/opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqloci.so&quot;
Found metadata in lib /opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqloci.so, metadata=
{
    &quot;IID&quot;: &quot;org.qt-project.Qt.QSqlDriverFactoryInterface&quot;,
    &quot;MetaData&quot;: {
        &quot;Keys&quot;: [
            &quot;QOCI8&quot;,
            &quot;QOCI&quot;
        ]
    },
    &quot;className&quot;: &quot;QOCIDriverPlugin&quot;,
    &quot;debug&quot;: false,
    &quot;version&quot;: 329985
}


Got keys from plugin meta data (&quot;QOCI8&quot;, &quot;QOCI&quot;)
QFactoryLoader::QFactoryLoader() looking at &quot;/opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqlpsql.so&quot;
Found metadata in lib /opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqlpsql.so, metadata=
{
    &quot;IID&quot;: &quot;org.qt-project.Qt.QSqlDriverFactoryInterface&quot;,
    &quot;MetaData&quot;: {
        &quot;Keys&quot;: [
            &quot;QPSQL7&quot;,
            &quot;QPSQL&quot;
        ]
    },
    &quot;className&quot;: &quot;QPSQLDriverPlugin&quot;,
    &quot;debug&quot;: false,
    &quot;version&quot;: 329985
}


Got keys from plugin meta data (&quot;QPSQL7&quot;, &quot;QPSQL&quot;)
loaded library &quot;/opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqloci.so&quot;
open db
QLibraryPrivate::unload succeeded on &quot;/opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqloci.so&quot; &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;Got keys from plugin meta data (&quot;QOCI8&quot;, &quot;QOCI&quot;)
QFactoryLoader::QFactoryLoader() looking at &quot;/opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqlpsql.so&quot;
Found metadata in lib /opt/Qt5.9.1/5.9.1/gcc_64/plugins/sqldrivers/libqsqlpsql.so, metadata=
{
    &quot;IID&quot;: &quot;org.qt-project.Qt.QSqlDriverFactoryInterface&quot;,
    &quot;MetaData&quot;: {
        &quot;Keys&quot;: [
            &quot;QPSQL7&quot;,
            &quot;QPSQL&quot;
        ]
    },
    &quot;className&quot;: &quot;QPSQLDriverPlugin&quot;,
    &quot;debug&quot;: false,
    &quot;version&quot;: 329985
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;QOCI&lt;/code&gt; 관련 메시지가 출력되면, 정상적으로 Driver가 로드된 것이다.&lt;/p&gt;</description>
      <category>Programming/QT</category>
      <category>db</category>
      <category>OCI</category>
      <category>QOCI</category>
      <category>QT</category>
      <category>QT OCI</category>
      <category>QT Oracle</category>
      <category>QT 오라클</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/60</guid>
      <comments>https://stackov.tistory.com/60#entry60comment</comments>
      <pubDate>Mon, 28 Jun 2021 18:34:54 +0900</pubDate>
    </item>
    <item>
      <title>NET::ERR_CERT_DATE_INVALID 해결법</title>
      <link>https://stackov.tistory.com/59</link>
      <description>&lt;p&gt;자취방을 이사하게 된 후, 갑작스럽게 많은 사이트들이 접속이 불가능한 오류가 발생했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X7XRU/btqECLXdNzs/09geH4lCcpz1xTwCFyWMo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X7XRU/btqECLXdNzs/09geH4lCcpz1xTwCFyWMo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X7XRU/btqECLXdNzs/09geH4lCcpz1xTwCFyWMo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX7XRU%2FbtqECLXdNzs%2F09geH4lCcpz1xTwCFyWMo1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위 사진과 쿠팡, 네이버 등을 포함한 많은 사이트들에 접속할 시 위와 같은 오류 메시지를 출력했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 오류 메시지는 &lt;b&gt;NET::ERR_CERT_DATE_INVALID&lt;/b&gt;로 SSL을 사용중인 많은 사이트들에 접근이 제한된 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;해결방법을 찾던 중 &lt;b&gt;루트 인증서&lt;/b&gt;가 자동으로 업데이트 되지 않아 발생 한 것이다는 글을 보게 되었고, 이를 참고하여 오류를 수정하였다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;수정 방법은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. 레지스트리 편집기를 실행한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;시작 -&amp;gt; 실행 (Windows + R) -&amp;gt; regedit&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFaZua/btqEChoMRhm/O2Ik2XkVZdoSwXxek139s1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFaZua/btqEChoMRhm/O2Ik2XkVZdoSwXxek139s1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFaZua/btqEChoMRhm/O2Ik2XkVZdoSwXxek139s1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFaZua%2FbtqEChoMRhm%2FO2Ik2XkVZdoSwXxek139s1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;2. 실행된 레지스트리 편집기에서 &lt;span style=&quot;color: #000000;&quot;&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\AuthRoot 를 찾는다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DtH5e/btqECvG6SuU/Z09VcDoj4ZwT2D1znKWv5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DtH5e/btqECvG6SuU/Z09VcDoj4ZwT2D1znKWv5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DtH5e/btqECvG6SuU/Z09VcDoj4ZwT2D1znKWv5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDtH5e%2FbtqECvG6SuU%2FZ09VcDoj4ZwT2D1znKWv5k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;상단의 주소줄에 입력후 엔터를 치면 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;3. DisableRootAutoUpdate 의 값을 0으로 변경한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zKM19/btqEBoaSNBT/4Z021iy11HJAXNPrkFQrH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zKM19/btqEBoaSNBT/4Z021iy11HJAXNPrkFQrH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zKM19/btqEBoaSNBT/4Z021iy11HJAXNPrkFQrH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzKM19%2FbtqEBoaSNBT%2F4Z021iy11HJAXNPrkFQrH0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;위의 항목을 보면 값이 1로 설정되어 있을 것이다. 이 항목을 더블클릭 하여 아래와 같은 창이 나오면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWlT2Y/btqEC7Z3LvO/u79KXMzhGNkBw9aVY7yuS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWlT2Y/btqEC7Z3LvO/u79KXMzhGNkBw9aVY7yuS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWlT2Y/btqEC7Z3LvO/u79KXMzhGNkBw9aVY7yuS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWlT2Y%2FbtqEC7Z3LvO%2Fu79KXMzhGNkBw9aVY7yuS0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;값을 0으로 변경 후 확인 을 클릭한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;4. 재부팅&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;위의 과정을 수행하면 루트 인증서가 자동 업데이트 되며, 설정 이후부터 오류 메시지 없이 정상 작동이 됨을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OS</category>
      <category>DisableRootAutoUpdate</category>
      <category>NET::ERR_CERT_DATE_INVALID</category>
      <category>SSL 오류</category>
      <category>루트인증서</category>
      <category>루트인증서 자동업데이트</category>
      <category>연결이 비공개로</category>
      <category>인터넷 오류</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/59</guid>
      <comments>https://stackov.tistory.com/59#entry59comment</comments>
      <pubDate>Thu, 4 Jun 2020 00:17:34 +0900</pubDate>
    </item>
    <item>
      <title>[CentOS] Gnome 설정화면을 X11 forwarding 에서 실행하기</title>
      <link>https://stackov.tistory.com/58</link>
      <description>&lt;p&gt;ssh를 X11 forwarding 상태로 실행 후 아래의 명령어를 입력하면 Gnome control center가 실행된다.&lt;/p&gt;
&lt;p&gt;env XDG_CURRENT_DESKTOP=GNOME gnome-control-center&lt;/p&gt;
&lt;p&gt;Display등의 설정은 불가능하지만 다른 설정들은 가능하다.&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/58</guid>
      <comments>https://stackov.tistory.com/58#entry58comment</comments>
      <pubDate>Tue, 2 Jun 2020 13:25:06 +0900</pubDate>
    </item>
    <item>
      <title>[CentOS 7] Gnome환경에서 ssh를 이용하여 Display 항상 켜기로 설정</title>
      <link>https://stackov.tistory.com/57</link>
      <description>&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gsettings set org.gnome.desktop.session idle-delay 0
gsettings set org.gnome.desktop.screensaver lock-enabled false&lt;/code&gt;&lt;/pre&gt;</description>
      <category>OS/Linux</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/57</guid>
      <comments>https://stackov.tistory.com/57#entry57comment</comments>
      <pubDate>Tue, 2 Jun 2020 11:08:19 +0900</pubDate>
    </item>
    <item>
      <title>[Git] Remote에서 삭제된 Branch, Local에서도 제거하기</title>
      <link>https://stackov.tistory.com/56</link>
      <description>&lt;p&gt;일반적으로, &lt;code&gt;pull&lt;/code&gt; 또는 &lt;code&gt;fetch&lt;/code&gt; 명령어를 통해 가져온 Remote branch 정보는 Remote에서 삭제 되더라도 계속해서 리스트에서 제거되지 않는다.&lt;/p&gt;
&lt;p&gt;따라서 이를 제거하기 위해 일반적으로는 &lt;code&gt;git fetch --prune&lt;/code&gt; 명령어를 통해 삭제된 branch를 리스트에서 제거하는 작업을 수행한다.&lt;/p&gt;
&lt;p&gt;하지만 이와 같은 동작은 Remote branch의 정보만 업데이트하며, checkout된 local branch 목록에서는 지워지지 않는다.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;이를 해결하기 위해선 아래와 같은 명령어를 실행하면 손쉽게 해결할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;git branch -r |
awk '{print $1}' |
egrep -v -f /dev/fd/0 &amp;lt;(git branch -vv | grep origin) |
awk '{print $1}' |
xargs git branch -d&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 명령어 입력 시 삭제된 branch의 명단이 나타나며 자동으로 checkout 된 branch가 삭제된다.&lt;/p&gt;</description>
      <category>Code/git</category>
      <category>branch 제거</category>
      <category>git</category>
      <category>Remote</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/56</guid>
      <comments>https://stackov.tistory.com/56#entry56comment</comments>
      <pubDate>Wed, 29 Apr 2020 16:14:09 +0900</pubDate>
    </item>
    <item>
      <title>CentOS + QTCreator 환경에서 Distcc 빌드 설정하기</title>
      <link>https://stackov.tistory.com/55</link>
      <description>&lt;p&gt;CentOS 환경에서 QT와 CPP를 이용하여 프로젝트를 개발하고 있다. 프로그램의 규모가 커진 만큼 프로젝트를 빌드하기 위해 많은 시간이 소요되며, 빌드 과정중에 CPU 및 Memory 소모량 역시 증가했다.&lt;/p&gt;
&lt;p&gt;또한 각 프로그램이 구동되기 위해 필요한 프로그램 들도 Memory 점유율이 높은 상태여서 개발 PC의 Memory가 항상 부족한 상태다.&lt;/p&gt;
&lt;p&gt;이러한 상황에서 테스트 및 기능 수정 도중 빌드를 시작하면 시스템이 다운되고, 재부팅을 해야 하는 등의 문제가 많은 상태다.&lt;/p&gt;
&lt;p&gt;빌드에 소요되는 시간 및 메모리 점유율을 낮추기 위해 윈도우에서 많이 사용되는 IncrediBuild와 같은 솔루션의 리눅스판을 찾아 보았고, &lt;code&gt;distcc&lt;/code&gt;라는 훌륭한 프로그램을 발견했다.&lt;/p&gt;
&lt;p&gt;해당 프로그램에 대한 설명은 주로 cmake와 관련되어 설명이 되어있고, QT Creator에서 바로 사용하는 방법에 대한 자료를 찾지 못하였고, 많은 시행착오 끝에 정리된 과정을 글로 남기기로 하였다.&lt;/p&gt;
&lt;p&gt;본 게시글은 CentOS 7.X 환경에 QTCreator와 Development Tool이 설치되어있다고 가정하고 작성하였다.&lt;/p&gt;
&lt;h2&gt;0. Distcc 정의&lt;/h2&gt;
&lt;p&gt;Client : 빌드 요청을 하는 개발PC&lt;/p&gt;
&lt;p&gt;Server : 빌드 요청을 수신하여 빌드를 수행하는 PC&lt;/p&gt;
&lt;h2&gt;1. Distcc 설치하기.&lt;/h2&gt;
&lt;p&gt;아래의 명령어를 통해 Distcc를 설치한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo yum install &amp;quot;distcc*&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위의 명령을 통해 distcc와 관련된 모든 프로그램(distcc, distcc server, distcc monitor)을 설치해 준다.&lt;/p&gt;
&lt;h2&gt;2. Server 설정하기&lt;/h2&gt;
&lt;p&gt;먼저, &lt;code&gt;/etc/sysconfig/distccd&lt;/code&gt;를 수정하여 허용할 host 및 core수 등을 설정한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;### See distcc(1) manual page for more information on these options.
###

USER=&amp;quot;distcc&amp;quot;

### Set this if don&amp;#39;t want distccd to use gcc or g++ by accident.
#DISTCCPATH=&amp;quot;/usr/lib/distcc/bin&amp;quot;
OPTIONS=&amp;quot;--nice (우선순위) --jobs (코어수) --allow 192.168.0.0/24&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위의 예시에서 &lt;code&gt;--allow&lt;/code&gt; 옵션이 요청을 허용할 host의 ip범위이다. 위의 예제는 192.168.0.X 대역의 모든 요청을 허용한다는 의미다.&lt;/p&gt;
&lt;p&gt;만일 단일 IP만 허용하고 싶으면 &lt;code&gt;--allow IP&lt;/code&gt;로 설정하면 되며, 여러개의 IP를 설정하고 싶으면 &lt;code&gt;--allow IP&lt;/code&gt;를 여러번 반복 입력해주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--port 포트번호&lt;/code&gt; 옵션을 추가해 주면 distcc의 포트 번호도 변경 가능하다.&lt;/p&gt;
&lt;p&gt;설정이 완료되면 데몬을 추가하고 실행해 준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable distccd
sudo systemctl start distccd&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위의 명령어 까지 실행하면, Distcc 서버의 설정은 완료되었다.&lt;/p&gt;
&lt;p&gt;distcc서버 역할을 할 pc가 많을 경우 여러 대의 서버에 위의 설정을 추가해주면 된다.&lt;/p&gt;
&lt;h2&gt;3. Client 설정하기&lt;/h2&gt;
&lt;p&gt;client는 빌드 요청을 할 server의 목록을 &lt;code&gt;/etrc/distcc/hosts&lt;/code&gt; 파일에 서버마다 하나의 라인으로 &lt;code&gt;HOST:PORT/JOB&lt;/code&gt; 형식으로 추가하면 된다.&lt;/p&gt;
&lt;p&gt;아래 예시는 다음과 같은 시나리오에 대한 예시다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;서버 종류&lt;ul&gt;
&lt;li&gt;192.168.0.1&lt;/li&gt;
&lt;li&gt;192.168.0.2&lt;/li&gt;
&lt;li&gt;192.168.0.3&lt;ul&gt;
&lt;li&gt;포트 번호 재설정 : 1234&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;local PC는 빌드에 사용하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각 서버에 Job을 10개씩 할당&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;192.168.0.1/10
192.168.0.2/10
192.168.0.3:1234/10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 설정이 완료되면 &lt;code&gt;distcc --show-hosts&lt;/code&gt; 명령어를 통해 설정이 잘 되었는지 확인이 가능하다.&lt;/p&gt;
&lt;h2&gt;4. QT Creator 설정&lt;/h2&gt;
&lt;p&gt;QT Creator에서 간단한 설정을 통해 distcc를 이용한 빌드 수행이 가능하다.&lt;/p&gt;
&lt;p&gt;먼저, 현재 개발중인 프로젝트를 불러온 뒤, 좌측의 Projects 탭으로 이동한 뒤 Build &amp;amp; Run 하단의 Build 를 선택한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DFgOD/btqDhvBNBbA/ikbGUojatb0c2vmR4VHY2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DFgOD/btqDhvBNBbA/ikbGUojatb0c2vmR4VHY2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DFgOD/btqDhvBNBbA/ikbGUojatb0c2vmR4VHY2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDFgOD%2FbtqDhvBNBbA%2FikbGUojatb0c2vmR4VHY2K%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Build Steps의 Make에 Details를 클릭한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xk8oi/btqDgzkoPqW/b9sKbedmpekeUXFkAK1cTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xk8oi/btqDgzkoPqW/b9sKbedmpekeUXFkAK1cTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xk8oi/btqDgzkoPqW/b9sKbedmpekeUXFkAK1cTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXk8oi%2FbtqDgzkoPqW%2Fb9sKbedmpekeUXFkAK1cTk%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;그럼 위와 같은 부분이 확장되며 나타나는데, &lt;code&gt;Make argumentws:&lt;/code&gt; 항목에&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-j (Job수) CXX=&amp;quot;distcc g++&amp;quot; CC=&amp;quot;distcc gcc&amp;quot;&lt;/code&gt; 를 입력한다.&lt;/p&gt;
&lt;p&gt;그 후 빌드를 수행하면 distcc를 이용한 분산 빌드가 수행된다.&lt;/p&gt;
&lt;h2&gt;5. Distcc 작동 확인&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;과정 1&lt;/code&gt; 에서 설치한 distcc monitor를 이용하여 빌드 상태 확인이 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;distccmon-gnome&lt;/code&gt; 명령어를 이용하여 모니터 프로그램을 실행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6Yiap/btqDeJ9kiZD/VevVjiau13FI45yoYkQILk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6Yiap/btqDeJ9kiZD/VevVjiau13FI45yoYkQILk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6Yiap/btqDeJ9kiZD/VevVjiau13FI45yoYkQILk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6Yiap%2FbtqDeJ9kiZD%2FVevVjiau13FI45yoYkQILk%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;그 후 빌드를 수행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzwaVa/btqDhvaKcM5/7JOJ7qY2ZSt70PRZLwSO21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzwaVa/btqDhvaKcM5/7JOJ7qY2ZSt70PRZLwSO21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzwaVa/btqDhvaKcM5/7JOJ7qY2ZSt70PRZLwSO21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzwaVa%2FbtqDhvaKcM5%2F7JOJ7qY2ZSt70PRZLwSO21%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;(파일 및 IP일부는 제거하였습니다.)&lt;/p&gt;
&lt;p&gt;빌드를 수행하는 순간, 연결된 각 host의 build 상태가 표기된다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;distcc를 사용해본 결과 전체 rebuild 속도가 상당히 빨라졌다. 또한 build에 리소스를 많이 사용하여 시스템이 멈추는 현상도 감소했다.&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/55</guid>
      <comments>https://stackov.tistory.com/55#entry55comment</comments>
      <pubDate>Wed, 8 Apr 2020 11:13:12 +0900</pubDate>
    </item>
    <item>
      <title>[Git] 실수로 날린 Branch의 Commit 복구하기</title>
      <link>https://stackov.tistory.com/54</link>
      <description>&lt;p&gt;최근 Remote의 Branch를 제거하던 중 아직 개발중인 Branch를 삭제하는 일이 발생했다.&lt;/p&gt;
&lt;p&gt;다행히 해당 Branch에 대해 Merge Request를 생성해서 관리하고 있었고, 이에 대한 Commit hash 기록이 남아있어 일부 복구가 가능했다.&lt;/p&gt;
&lt;p&gt;하지만, 미처 기록이 남지 않은 커밋이 있었고, 이를 복구하기위해 여러가지 방안을 찾아보았고, 아래의 방법을 사용하면 쉽게 찾을 수 있었다.&lt;/p&gt;
&lt;pre id=&quot;code_1575609417046&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git reflog | awk '{ print $1 }' | xargs gitk&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 명령어는 최근 60일 이내의 log를 다시 볼 수 있었고, 이를 통해 Commit 정보를 받아와 gitk를 이용해 최근 Commit Log를 Graph화 하여 볼 수 있었다.&lt;/p&gt;
&lt;p&gt;앞으로는 삭제할 때 조금 더 신중히 해야겠다.&lt;/p&gt;</description>
      <category>Code/git</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/54</guid>
      <comments>https://stackov.tistory.com/54#entry54comment</comments>
      <pubDate>Fri, 6 Dec 2019 14:17:48 +0900</pubDate>
    </item>
    <item>
      <title>[CentOS] 최신 버전의 Git으로 업데이트 하기</title>
      <link>https://stackov.tistory.com/53</link>
      <description>&lt;p&gt;CentOS 7.X 버전에서는 git이 1.8 버전으로 설치가 되어있다.&lt;/p&gt;
&lt;p&gt;하지만, VSCode나 깃의 최신 버전을 이용함에 있어 여러가지 불편사항이 존재한다.&lt;/p&gt;
&lt;p&gt;이를 해결하기 위해 git 최신버전을 설치하는 방법을 작성하고자 한다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;git을 업데이트 하기 위해, 최신버전의 git이 저장되어 있는 저장소를 시스템에 추가한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rpm -Uvh http://opensource.wandisco.com/centos/7/git/x86_64/wandisco-git-release-7-2.noarch.rpm&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;그 후 yum을 이용해 git의 최신버전을 설치한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yum update git&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위의 명령어를 입력할 경우 git의 종속 모듈을 포함하여 최신 버전의 git이 설치된다.&lt;/p&gt;
&lt;p&gt;그 이후 아래의 명령어를 입력하면 최신 버전의 깃이 설치된 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git --version&lt;/code&gt;&lt;/pre&gt;</description>
      <category>OS/Linux</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/53</guid>
      <comments>https://stackov.tistory.com/53#entry53comment</comments>
      <pubDate>Wed, 17 Jul 2019 09:51:34 +0900</pubDate>
    </item>
    <item>
      <title>[Git] Sub directory를 새 저장소에 옮기고 sub module로 변경하기</title>
      <link>https://stackov.tistory.com/52</link>
      <description>&lt;p&gt;코드를 관리하면서, 여러 프로젝트에서 동일한 코드를 사용하게 되는 경우가 종종 발생한다. 이러한 상황이 발생하게 될 경우&amp;nbsp; 보통은 코드의 복사/붙여넣기를 통해 코드를 관리하게 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이러한 복사/붙여넣기 방식은 코드 관리에 어려움을 겪게 될 수 있는데, 어떤 프로젝트에는 반영된 부분이 다른 프로젝트에는 반영이 되거나 누락되는 경우가 흔히 발생하게 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이러한 부분은 git을 사용할 경우 공통된 부분의 코드에 대해 sub module 기능을 이용하여 분리하게 될 경우 편리하게 개선 할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;sub module이란&lt;/b&gt;&amp;nbsp;파일을 직접 갖는게 아니라 다른 코드 저장소(repository)에 있는 코드를 링크만 하는 방식이다. 이러한 특성을 이용하여 공통된 부분을 폴더로 분리하고 별도의 저장소로 분리한 뒤 해당 모듈을 사용하는 프로젝트에서 간단히 submodule로 추가만 할 경우 공통 부분에 대해 별도의 코드 관리를 거치지 않아도 변경이력을 관리할 수 있으며, 다른 프로젝트에도 손쉽게 적용할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Sub Module을 사용하기에 앞서, 예제에 사용될 Project의 상황에 대해 다음과 같은 가정을 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;box&quot;&gt;- Project는&amp;nbsp;&lt;b&gt;A, B&lt;/b&gt;&amp;nbsp;가 존재하며, 서로 다른 저장소에 저장되어있다.&lt;br /&gt;- Local에서&amp;nbsp;&lt;b&gt;/code/A&lt;/b&gt;, &lt;b&gt;/code/B&lt;/b&gt;에 clone하여 사용하고 있는 상태이다.&lt;br /&gt;- Project &lt;b&gt;A, B&lt;/b&gt;는 &lt;b&gt;http://server.git/A&lt;/b&gt;,&amp;nbsp;&lt;b&gt;http://server.git/B&lt;/b&gt; 저장소에 저장되어 있다.&lt;br /&gt;- Project&amp;nbsp;&lt;b&gt;A&lt;/b&gt;&amp;nbsp;및&amp;nbsp;&lt;b&gt;B&lt;/b&gt;에서&amp;nbsp;&lt;b&gt;module/XmlReader&lt;/b&gt;&amp;nbsp;라는 공통의 폴더를 갖고 있으며, 동시에 사용 중이다.&lt;br /&gt;- Project&amp;nbsp;&lt;b&gt;A, B&lt;/b&gt;의&amp;nbsp;&lt;b&gt;module/XmlReader&lt;/b&gt;는 코드가 동일한 상태이다.&lt;br /&gt;- &lt;b&gt;module/XmlReader&lt;/b&gt;의 코드를 분리하여&amp;nbsp;&lt;b&gt;http://server.git/XmlReader&lt;/b&gt;&amp;nbsp;저장소에 저장한다.&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;본문에서는 예제에서 이 &lt;b&gt;XmlReader&lt;/b&gt;를 새 저장소로 분리하고, Submodule로 &lt;b&gt;A, B&lt;/b&gt;에 추가하는 방법에 대해 작성할 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;b&gt;1. 공통 코드 쪼개기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;코드를 쪼개는 순서는 다음과 같이 진행된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;subtree로 branch 쪼개기 -&amp;gt; branch를 저장소에 push&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;공통 코드인 &lt;b&gt;XmlReader&lt;/b&gt;를 쪼개기 위해 directory의 코드를 분리하여 local branch에 옮긴다.&lt;/p&gt;
&lt;pre id=&quot;code_1562227129706&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd /code/A
git subtree split -P module/XmlReader -b tmp_XmlReader&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 명령어의 결과로&amp;nbsp;&lt;b&gt;A&lt;/b&gt; 프로젝트의&amp;nbsp;&lt;b&gt;module/XmlReader&amp;nbsp;&lt;/b&gt;폴더의&amp;nbsp;하위에 있는&amp;nbsp;코드 및 파일들이&amp;nbsp;&lt;b&gt;branch tmp_XmlReader&lt;/b&gt;로 분리된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;p&gt;branch로 분리가 되었으면&amp;nbsp;&lt;b&gt;XmlReader&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;의 저장소를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;A&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;프로젝트의 원격 저장소로 추가한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1562227338434&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git remote add proj_XmlReader http://server.git/XmlReader
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 명령어의 결과로 A 프로젝트에&amp;nbsp;&lt;b&gt;XmlReader&lt;/b&gt;의 원격 저장소를 &lt;b&gt;proj_XmlReader&lt;/b&gt;로 추가된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;p&gt;이제, Remote 저장소에 XmlReader의 코드들을 push 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1562227519134&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git push proj_XmlReader tmp_XmlReader:master&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 명령어를 통해 &lt;b&gt;XmlReader&lt;/b&gt; 저장소의 &lt;b&gt;master&lt;/b&gt; 브랜치로&amp;nbsp;첫번째 단계에서 분리한 &lt;b&gt;branch tmp_XmlReader&lt;/b&gt;를 전송하였다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이를 통해 Project A의 코드 중 XmlReader에 대한 코드가 별도의 저장소에 분리가 되었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;b&gt;2. 공통 코드를 Sub module로 처리하기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;코드를 쪼갰지만, 아직까지는 Project &lt;b&gt;A&lt;/b&gt; 및 &lt;b&gt;B&lt;/b&gt;에&amp;nbsp;&lt;b&gt;module/XmlReader&lt;/b&gt;에 코드가 그대로 있는 상태다.&lt;/p&gt;
&lt;p&gt;이를 개선하기 위해 기존의 파일을 제거하고 Sub module로 처리 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;먼저, Project&amp;nbsp;&lt;b&gt;A&lt;/b&gt;및 &lt;b&gt;B &lt;/b&gt;에서&amp;nbsp; 파일을 지워준다.&lt;/p&gt;
&lt;pre id=&quot;code_1562227909594&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd /code/A
rm -rf module/XmlReader
cd /code/B
rm -rf module/XmlReader&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그 다음 각 project에 sub module로 XmlReader를 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1562227983909&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd /code/A
git submodule add http://server.git/XmlReader module/XmlReader
cd /code/B
git submodule add http://server.git/XmlReader module/XmlReader&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 명령어를 통해 A 및 B에 submodule이 생성되었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;마지막으로, submodule 처리에 대한 커밋을 수행한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1562228039231&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd /code/A
git commit -m 'replaced module/XmlReader with a submodule'
cd /code/B
git commit -m 'replaced module/XmlReader with a submodule'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 과정을 통해 공통 코드를 submodule로 관리할 수 있게 되었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;위의 과정을 통해 Submodule로 분리하였지만,&amp;nbsp;&amp;nbsp;여러 이유를 통해 Project &lt;b&gt;A&lt;/b&gt; 및 &lt;b&gt;B&lt;/b&gt;를 clone할 경우 submodule에 대한 코드를 clone하지 않는다.&lt;/p&gt;
&lt;p&gt;이는 sub module은 별도의 repository기 때문에 사용자가 직접 init/update를 해줘야 한다.&lt;/p&gt;
&lt;p&gt;하지만 명령어에&lt;b&gt;&amp;nbsp;--recurse-submodules&amp;nbsp;&lt;/b&gt;옵션을 추가하여 자동으로 처리되도록 할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1562228266109&quot; class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git clone --recurse-submodules http://server.git/A&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p&gt;위와 같은 방법으로 코드를 쪼개고, 별도의 저장소로 분리를 하는 과정은 귀찮을 수 있지만 한번 적용하고 사용하게 될 경우 코드 관리를 함에 있어 신경써야 할 부분이 줄게 되어 편리해 질 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;참고자료 :&amp;nbsp;&lt;a href=&quot;https://coderwall.com/p/a3a5xg/splitting-a-project-sub-directory-to-a-new-git-repo&quot;&gt;https://coderwall.com/p/a3a5xg/splitting-a-project-sub-directory-to-a-new-git-repo&lt;/a&gt;&lt;/p&gt;</description>
      <category>Code/git</category>
      <category>Branch</category>
      <category>git</category>
      <category>Remote</category>
      <category>repository</category>
      <category>sub directory</category>
      <category>submodule</category>
      <category>subtree</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/52</guid>
      <comments>https://stackov.tistory.com/52#entry52comment</comments>
      <pubDate>Thu, 4 Jul 2019 17:20:09 +0900</pubDate>
    </item>
    <item>
      <title>[svn] svn code export : svn에서 코드를 export 해오기</title>
      <link>https://stackov.tistory.com/51</link>
      <description>&lt;p&gt;&lt;b&gt;svn&lt;/b&gt;을 사용하다보면&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;github&lt;/b&gt;에서 &lt;b&gt;zip download&lt;/b&gt;와 유사하게&lt;/span&gt; 코드의 수정 이력과 같은 정보 없이 데이터만을 &lt;b&gt;export&lt;/b&gt; (download) 가져올 경우가 종종 존재한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이러한 동작을 위해 svn에서는 &lt;b&gt;export&amp;nbsp;&lt;/b&gt;라는 기능을 제공하고 있으며, 필요시 특정 revision에 대한 코드만을 가져올 수도 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;svn export에 대한 help 정보는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;normal&quot;&gt;export:&amp;nbsp;버전관리&amp;nbsp;정보&amp;nbsp;없는&amp;nbsp;깨끗한&amp;nbsp;사본을&amp;nbsp;받아옵니다.&lt;br /&gt;사용법:&amp;nbsp;1.&amp;nbsp;export&amp;nbsp;[-r&amp;nbsp;REV]&amp;nbsp;URL[@PEGREV]&amp;nbsp;[PATH]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2.&amp;nbsp;export&amp;nbsp;[-r&amp;nbsp;REV]&amp;nbsp;PATH1[@PEGREV]&amp;nbsp;[PATH2]&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;1.&amp;nbsp;리비전&amp;nbsp;REV에&amp;nbsp;해당하는&amp;nbsp;URL&amp;nbsp;의&amp;nbsp;내용을&amp;nbsp;PATH에&amp;nbsp;받아&amp;nbsp;옵니다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;만약&amp;nbsp;REV가&amp;nbsp;지정되지&amp;nbsp;않으면&amp;nbsp;HEAD(최신&amp;nbsp;리비전)를&amp;nbsp;받아&amp;nbsp;옵니다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PATH가&amp;nbsp;생략되면&amp;nbsp;URL의&amp;nbsp;마지막&amp;nbsp;요소를&amp;nbsp;받아올&amp;nbsp;디렉토리&amp;nbsp;이름으로&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;사용합니다.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;2.&amp;nbsp;리비전&amp;nbsp;REV에&amp;nbsp;해당하는&amp;nbsp;PATH1으로&amp;nbsp;지정된&amp;nbsp;작업&amp;nbsp;사본의&amp;nbsp;내용을&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PATH2에&amp;nbsp;받아옵니다.&amp;nbsp;REV&amp;nbsp;가&amp;nbsp;생략되면&amp;nbsp;현재&amp;nbsp;작업중인&amp;nbsp;내용을&amp;nbsp;그대로&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;받아&amp;nbsp;옵니다.&amp;nbsp;PATH2가&amp;nbsp;생략되면&amp;nbsp;PATH1의&amp;nbsp;마지막&amp;nbsp;요소를&amp;nbsp;디렉토리&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;이름으로&amp;nbsp;사용합니다.&amp;nbsp;REV가&amp;nbsp;생략될&amp;nbsp;경우&amp;nbsp;작업&amp;nbsp;중에&amp;nbsp;변경된&amp;nbsp;내용은&amp;nbsp;그대로&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;유지되며,&amp;nbsp;버전&amp;nbsp;관리&amp;nbsp;대상이&amp;nbsp;아닌&amp;nbsp;파일들은&amp;nbsp;복사되지&amp;nbsp;않습니다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;PEGREV가&amp;nbsp;지정될&amp;nbsp;경우엔,&amp;nbsp;어떤&amp;nbsp;리비젼에서&amp;nbsp;대상을&amp;nbsp;먼저&amp;nbsp;찾을지&amp;nbsp;결정합니다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;옵션:&lt;br /&gt;&amp;nbsp;&amp;nbsp;-r&amp;nbsp;[--revision]&amp;nbsp;ARG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;ARG&amp;nbsp;(어떤&amp;nbsp;명령은&amp;nbsp;ARG1:ARG2&amp;nbsp;와&amp;nbsp;같은&amp;nbsp;범위를&amp;nbsp;사용)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;리비전은&amp;nbsp;다음&amp;nbsp;중&amp;nbsp;하나가&amp;nbsp;될&amp;nbsp;수&amp;nbsp;있습니다:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NUMBER&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;리비전&amp;nbsp;번호&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'{'&amp;nbsp;DATE&amp;nbsp;'}'&amp;nbsp;리비전이&amp;nbsp;시작하는&amp;nbsp;시각&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'HEAD'&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;저장소의&amp;nbsp;마지막&amp;nbsp;리비전&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'BASE'&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;작업&amp;nbsp;사본을&amp;nbsp;꺼내온&amp;nbsp;리비전&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'COMMITTED'&amp;nbsp;&amp;nbsp;BASE&amp;nbsp;이전에&amp;nbsp;마지막&amp;nbsp;커밋된&amp;nbsp;리비전&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'PREV'&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;COMMITTED&amp;nbsp;의&amp;nbsp;직전&amp;nbsp;리비전&lt;br /&gt;&amp;nbsp;&amp;nbsp;-q&amp;nbsp;[--quiet]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;아무것도&amp;nbsp;출력하지&amp;nbsp;않거나,&amp;nbsp;요약&amp;nbsp;정보만&amp;nbsp;출력합니다&lt;br /&gt;&amp;nbsp;&amp;nbsp;-N&amp;nbsp;[--non-recursive]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;사용금지;&amp;nbsp;대신&amp;nbsp;--depth=files,&amp;nbsp;--depth=immediates를&amp;nbsp;이용합니다&lt;br /&gt;&amp;nbsp;&amp;nbsp;--depth&amp;nbsp;ARG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;명령&amp;nbsp;적용&amp;nbsp;대상의&amp;nbsp;깊이를&amp;nbsp;제한&amp;nbsp;합니다&amp;nbsp;('empty',&amp;nbsp;'files'&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'emmediates',&amp;nbsp;'infinity')&lt;br /&gt;&amp;nbsp;&amp;nbsp;--force&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;강제로&amp;nbsp;실행합니다&lt;br /&gt;&amp;nbsp;&amp;nbsp;--native-eol&amp;nbsp;ARG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;행종료문자를&amp;nbsp;표준&amp;nbsp;시스템&amp;nbsp;문자가&amp;nbsp;아닌&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;파일의&amp;nbsp;svn:eol-style&amp;nbsp;속성을&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'native'로&amp;nbsp;두어&amp;nbsp;다른&amp;nbsp;것을&amp;nbsp;사용합니다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ARG는&amp;nbsp;'LF',&amp;nbsp;'CR',&amp;nbsp;'CRLF'&amp;nbsp;중의&amp;nbsp;하나가&amp;nbsp;될&amp;nbsp;수&amp;nbsp;있습니다&lt;br /&gt;&amp;nbsp;&amp;nbsp;--ignore-externals&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;외부&amp;nbsp;모듈(svn:externals로&amp;nbsp;지정된)은&amp;nbsp;무시합니다&lt;br /&gt;&amp;nbsp;&amp;nbsp;--ignore-keywords&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;내용중의&amp;nbsp;키워드를&amp;nbsp;치환하지&amp;nbsp;않습니다&lt;br /&gt;&lt;br /&gt;글로벌&amp;nbsp;옵션:&lt;br /&gt;&amp;nbsp;&amp;nbsp;--username&amp;nbsp;ARG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;ARG를&amp;nbsp;접속에&amp;nbsp;필요한&amp;nbsp;사용자&amp;nbsp;ID로&amp;nbsp;사용합니다&lt;br /&gt;&amp;nbsp;&amp;nbsp;--password&amp;nbsp;ARG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;specify&amp;nbsp;a&amp;nbsp;password&amp;nbsp;ARG&amp;nbsp;(caution:&amp;nbsp;on&amp;nbsp;many&amp;nbsp;operating&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;systems,&amp;nbsp;other&amp;nbsp;users&amp;nbsp;will&amp;nbsp;be&amp;nbsp;able&amp;nbsp;to&amp;nbsp;see&amp;nbsp;this)&lt;br /&gt;&amp;nbsp;&amp;nbsp;--no-auth-cache&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;인증&amp;nbsp;정보를&amp;nbsp;캐시에&amp;nbsp;저장하지&amp;nbsp;않습니다&lt;br /&gt;&amp;nbsp;&amp;nbsp;--non-interactive&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;do&amp;nbsp;no&amp;nbsp;interactive&amp;nbsp;prompting&amp;nbsp;(default&amp;nbsp;is&amp;nbsp;to&amp;nbsp;prompt&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;only&amp;nbsp;if&amp;nbsp;standard&amp;nbsp;input&amp;nbsp;is&amp;nbsp;a&amp;nbsp;terminal&amp;nbsp;device)&lt;br /&gt;&amp;nbsp;&amp;nbsp;--force-interactive&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;do&amp;nbsp;interactive&amp;nbsp;prompting&amp;nbsp;even&amp;nbsp;if&amp;nbsp;standard&amp;nbsp;input&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;is&amp;nbsp;not&amp;nbsp;a&amp;nbsp;terminal&amp;nbsp;device&lt;br /&gt;&amp;nbsp;&amp;nbsp;--trust-server-cert&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;deprecated;&amp;nbsp;same&amp;nbsp;as&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--trust-server-cert-failures=unknown-ca&lt;br /&gt;&amp;nbsp;&amp;nbsp;--trust-server-cert-failures&amp;nbsp;ARG&amp;nbsp;:&amp;nbsp;with&amp;nbsp;--non-interactive,&amp;nbsp;accept&amp;nbsp;SSL&amp;nbsp;server&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;certificates&amp;nbsp;with&amp;nbsp;failures;&amp;nbsp;ARG&amp;nbsp;is&amp;nbsp;comma-separated&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;list&amp;nbsp;of&amp;nbsp;'unknown-ca'&amp;nbsp;(Unknown&amp;nbsp;Authority),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'cn-mismatch'&amp;nbsp;(Hostname&amp;nbsp;mismatch),&amp;nbsp;'expired'&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(Expired&amp;nbsp;certificate),&amp;nbsp;'not-yet-valid'&amp;nbsp;(Not&amp;nbsp;yet&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;valid&amp;nbsp;certificate)&amp;nbsp;and&amp;nbsp;'other'&amp;nbsp;(all&amp;nbsp;other&amp;nbsp;not&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;separately&amp;nbsp;classified&amp;nbsp;certificate&amp;nbsp;errors).&lt;br /&gt;&amp;nbsp;&amp;nbsp;--config-dir&amp;nbsp;ARG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;ARG로&amp;nbsp;지정된&amp;nbsp;디렉토리에서&amp;nbsp;사용자&amp;nbsp;구성화일을&amp;nbsp;읽습니다&lt;br /&gt;&amp;nbsp;&amp;nbsp;--config-option&amp;nbsp;ARG&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;사용자&amp;nbsp;옵션의&amp;nbsp;포맷을&amp;nbsp;다음과&amp;nbsp;같이&amp;nbsp;지정합니다:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FILE:SECTION:OPTION=[VALUE]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;예:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;servers:global:http-library=serf&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;기본적인 export에 대한 명령 인자에 대한 설명은&amp;nbsp;&lt;b&gt;&lt;span&gt;export&amp;nbsp;[-r&amp;nbsp;REV]&amp;nbsp;URL[@PEGREV]&amp;nbsp;[PATH]&lt;/span&gt;&lt;/b&gt;&amp;nbsp;다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;REV:&amp;nbsp; 가져오고 싶은 revision 정보이며, 값을 지정하지 않으면 HEAD에 해당되는 파일을 자동으로 가져온다.&lt;/p&gt;
&lt;p&gt;URL : 저장소의 url을 의미한다.&lt;/p&gt;
&lt;p&gt;PATH : export한 파일의 저장 위치, 별다른 값을 지정하지 않으면 기본 값으로 URL에서 지정된 경로 중 마지막 값 (Directory명 또는 file명)으로 처리된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;예제&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;svn export를 수행하는 예시는 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1561704006236&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# repository url : http://svn.server/A
# revision : 10

svn export -r 10 http://svn.server/A&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위의 command를 실행하면 command를 실행한 위치에 A 디렉터리를 생성하며, 생성된 디렉터리 안에&amp;nbsp;&lt;a href=&quot;http://svn.server/A&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://svn.server/A&lt;/a&gt;&amp;nbsp;의 하위 항목들을 다운로드 한다. 이 때, rev. 10 코드를 가져온다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Code/svn</category>
      <category>export</category>
      <category>Path</category>
      <category>Revision</category>
      <category>SVN</category>
      <category>URL</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/51</guid>
      <comments>https://stackov.tistory.com/51#entry51comment</comments>
      <pubDate>Fri, 28 Jun 2019 15:41:59 +0900</pubDate>
    </item>
    <item>
      <title>[QT] static assertion failed: Type is not registered, please use the Q_DECLARE_METATYPE</title>
      <link>https://stackov.tistory.com/50</link>
      <description>&lt;p&gt;QT를 이용하여, 개발을 하다 보면 자주 만나는 메시지다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kEMLb/btqwmtKk4JL/r6CpqKaIg2oZ2pZgas3rV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kEMLb/btqwmtKk4JL/r6CpqKaIg2oZ2pZgas3rV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kEMLb/btqwmtKk4JL/r6CpqKaIg2oZ2pZgas3rV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkEMLb%2FbtqwmtKk4JL%2Fr6CpqKaIg2oZ2pZgas3rV1%2Fimg.png&quot; data-filename=&quot;blob&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;QVariant와 같은 QT에 미리 지정된 템플릿 클래스를 이용하다 보면 위와 같은 에러 메시지를 종 종 볼 수 있는데,&lt;/p&gt;
&lt;p&gt;사용자 정의 클래스/타입이 미리 선언되어있지 않아 발생하는 오류다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1561443478401&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum ENUM_TYPE {
	ENUM_1,
    ENUM_2
}


QVariant v;
v.value&amp;lt;ENUM_TYPE&amp;gt;(); // 에러&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이는&amp;nbsp;&amp;nbsp;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;헤더 파일에&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Q_DECLARE_METATYPE(TypeName)&amp;nbsp; 과 같이 작성하면 해당 문제는 해결된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1561443483549&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum ENUM_TYPE {
	ENUM_1,
    ENUM_2
}

Q_DECLARE_METATYPE(FSStatus);

QVariant v;
v.value&amp;lt;ENUM_TYPE&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/QT</category>
      <category>C</category>
      <category>C++</category>
      <category>compile</category>
      <category>error</category>
      <category>QT</category>
      <category>Q_DECLARE_METATYPE</category>
      <category>static assertion failed</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/50</guid>
      <comments>https://stackov.tistory.com/50#entry50comment</comments>
      <pubDate>Tue, 25 Jun 2019 15:19:17 +0900</pubDate>
    </item>
    <item>
      <title>[CentOS] SWAP 빈도 조절하여 성능 개선</title>
      <link>https://stackov.tistory.com/49</link>
      <description>&lt;p&gt;리눅스 시스템에서는 메모리가 부족해 질 경우 발생하는 오류 (메모리 할당 오류 등)를 방지하기 위해&amp;nbsp;SWAP 영역을 사용한다.&lt;/p&gt;
&lt;p&gt;SWAP 영역이란 메인 메모리의 공간이 부족해 질 때 메모리의 일부를 디스크에 저장하고, 사용하는 순간에만 잠시 메인 메모리(RAM)에 불러와 사용하기 위한 공간이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgF69F/btqwimd9tjF/9CXASAHy9vEKQgWKRHq4q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgF69F/btqwimd9tjF/9CXASAHy9vEKQgWKRHq4q0/img.png&quot; data-alt=&quot;디스크에 생성된 많은 파티션 중 하나가 SWAP영역으로 지정되어 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgF69F/btqwimd9tjF/9CXASAHy9vEKQgWKRHq4q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgF69F%2Fbtqwimd9tjF%2F9CXASAHy9vEKQgWKRHq4q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;디스크에 생성된 많은 파티션 중 하나가 SWAP영역으로 지정되어 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;OS, 커널의 정책마다 SWAP 영역으로 내보낼 메모리 를 선정하는 방법이 다르며, 어느 시점에 내려보낼지에 대한 설정도 제각각 이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;또한 같은 OS, 커널을 사용한다 하더라도 시스템 설정값의 변경을 통해 서로 다른 결과가 나타날 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Znmky/btqwgBw2Tb4/XEbmRSrxFIHDqYLh8O4cHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Znmky/btqwgBw2Tb4/XEbmRSrxFIHDqYLh8O4cHK/img.png&quot; data-alt=&quot;top을 통해 확인한 RAM/SWAP 영역의 사용량&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Znmky/btqwgBw2Tb4/XEbmRSrxFIHDqYLh8O4cHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZnmky%2FbtqwgBw2Tb4%2FXEbmRSrxFIHDqYLh8O4cHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;top을 통해 확인한 RAM/SWAP 영역의 사용량&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위의 사진과 같이 아직 메인 메모리의 공간이 남아 있음에도, 미리 SWAP영역으로 내보내는 경우가 발생하기도 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;CentOS에서는 스왑에 대한 정책을&amp;nbsp;&lt;i&gt;sysctl&amp;nbsp;&lt;/i&gt;또는 &lt;i&gt;/etc/sysctl.conf&amp;nbsp;&lt;/i&gt;을 통해&amp;nbsp;변경할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;스왑 적극도 값 변경 및 적용 (swappiness)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;메모리 스왑 횟수를 줄여, 스왑시 발생하는 속도 저하를 해결하기 위해선 swappiness 값을 변경해야 한다.&lt;/p&gt;
&lt;p&gt;이는 swap을 얼마나 적극적으로 활용하는지 대한 설정으로 이 설정은&amp;nbsp;&lt;i&gt;&lt;span&gt;vm&lt;/span&gt;&lt;span&gt;.swappine&lt;/span&gt;&lt;span&gt;ss&lt;/span&gt;&lt;/i&gt;&amp;nbsp;값의 변경을 통해 지정된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;값의 범위는 0~100으로 되어 있으며,&amp;nbsp;0이면 스왑을 사용하지 않고, 100이면 적극적으로 스왑을 사용하게 된다.&lt;/p&gt;
&lt;p&gt;값에 대한 설명은 아래 표와 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;값&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;스왑하지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;1~99&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;
&lt;p&gt;값이 커질수록 적극적으로 스왑&lt;/p&gt;
&lt;p&gt;작아질 수록 소극적으로 스왑&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;100&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;적극적으로 스왑&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vadh5/btqwhxHr2FP/QF8pXK0fDWwdqinasWiOK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vadh5/btqwhxHr2FP/QF8pXK0fDWwdqinasWiOK0/img.png&quot; data-alt=&quot;스왑 적극도의 기본 설정 값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vadh5/btqwhxHr2FP/QF8pXK0fDWwdqinasWiOK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvadh5%2FbtqwhxHr2FP%2FQF8pXK0fDWwdqinasWiOK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스왑 적극도의 기본 설정 값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;기본 설정은 60으로 되어있으며, 적극도는 설정된 값에 비례한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;sysctl 명령어를 이용하여 설정하면, 현재 부팅된 시스템에 임시적으로 적용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1561340651450&quot; class=&quot;go&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sysctl vm.swappiness=10 #원하는 설정값 입력, 예제에선 10&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 값을 쉘에 입력하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QNljK/btqwhTDgiVw/KkxrOVKOTr95ZLyXHPSCw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QNljK/btqwhTDgiVw/KkxrOVKOTr95ZLyXHPSCw0/img.png&quot; data-alt=&quot;swappiness 설정 예제&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QNljK/btqwhTDgiVw/KkxrOVKOTr95ZLyXHPSCw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQNljK%2FbtqwhTDgiVw%2FKkxrOVKOTr95ZLyXHPSCw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;swappiness 설정 예제&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;영구적으로 적용하기 위해선, &lt;i&gt;/etc/sysctl.conf&amp;nbsp;&lt;/i&gt;에 입력한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnnQeu/btqwjvuGslY/2mmaCz63ADzpW1tTasScO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnnQeu/btqwjvuGslY/2mmaCz63ADzpW1tTasScO0/img.png&quot; data-alt=&quot;/etc/sysctl.conf&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnnQeu/btqwjvuGslY/2mmaCz63ADzpW1tTasScO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnnQeu%2FbtqwjvuGslY%2F2mmaCz63ADzpW1tTasScO0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;/etc/sysctl.conf&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/49</guid>
      <comments>https://stackov.tistory.com/49#entry49comment</comments>
      <pubDate>Mon, 24 Jun 2019 10:49:19 +0900</pubDate>
    </item>
    <item>
      <title>[CentOS 7] Multicast Packet을 Loopback으로 송/수신</title>
      <link>https://stackov.tistory.com/48</link>
      <description>&lt;p&gt;본 포스트에는 centos의 lo interface (localhost interface)에 route를 추가하여 Multicast packet을 local pc로만 송/수신 하고, NIC카드를 통해 외부로 나가지 않도록 처리하는 방법에 대해 서술하고자 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;기본적으로, Multicast의 IP 대역은 아래와 같이 지정되어 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fw2dY/btqwfl7RAk4/zcjy5f6VBCwtj5iKv9LjC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fw2dY/btqwfl7RAk4/zcjy5f6VBCwtj5iKv9LjC0/img.png&quot; data-alt=&quot;Multicast IP range table (https://en.wikipedia.org/wiki/Multicast_address)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fw2dY/btqwfl7RAk4/zcjy5f6VBCwtj5iKv9LjC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFw2dY%2Fbtqwfl7RAk4%2Fzcjy5f6VBCwtj5iKv9LjC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Multicast IP range table (https://en.wikipedia.org/wiki/Multicast_address)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 중, 224.0.0.0 - 224.0.0.255가 Local range로 되어있으나, 이는 TTL이 1인 multicast packet을 생성 및 전송하는 역할을 수행한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서, 생성된 패킷은 네트워크를 태워 보내지게 되고, 로컬 망 내의 다른 장비들도 해당 패킷이 수신된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서 완벽한 Loopback을 위해 Multicast 관련 패킷이 local interface (default : lo)를 이용하여 local pc 내부에서만 돌도록 처리해야한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;hr&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다행히, 방법은 어렵지 않다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아래의 명령어를 이용하면, multicast 패킷이 local interface를 통해 송신 및 수신하게 되며, 외부망에 패킷을 태우지 않을 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1561099547086&quot; class=&quot;c++ cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo ifconfig lo multicast
sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev lo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;첫 번째 줄의 명령어는&amp;nbsp; interface &quot;lo&quot;에 multicast 패킷을 송수신 하도록 상태를 활성화 시켜준다.&lt;/p&gt;
&lt;p&gt;두 번째 줄의 명령어는 224.0.0.0, netmast 240.0.0.0에 해당되는 IP대역에 대한 패킷을 interface &quot;lo&quot;를 이용하여 통신하도록&amp;nbsp; Route 경로를 추가하는 역할을 수행한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;따라서 Multicast와 관련된 패킷들은 &quot;lo&quot; interface만을 통해 송신 및 수신하게 된다.&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <category>Bash</category>
      <category>centos</category>
      <category>centos 7</category>
      <category>Command</category>
      <category>Linux</category>
      <category>localhost</category>
      <category>loopback</category>
      <category>Multicast</category>
      <category>Route</category>
      <category>routing</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/48</guid>
      <comments>https://stackov.tistory.com/48#entry48comment</comments>
      <pubDate>Fri, 21 Jun 2019 15:49:14 +0900</pubDate>
    </item>
    <item>
      <title>[mysql/mariadb] Database export 하기 (db dump)</title>
      <link>https://stackov.tistory.com/47</link>
      <description>&lt;p&gt;DB Dump는 간단한 명령어를 통해 가능하다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mysqldump -u ID -p DBNAME &amp;gt; FILE_NAME&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ID, DBNAME, FILE_NAME에 적절한 값을 입력하면 된다.&lt;/p&gt;
&lt;p&gt;만일, Table의 데이터 없이 schema만 백업하고 싶으면 다음과 같은 명령어를 사용하면된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mysqldump -u ID -p --no-data DBNAME &amp;gt;FILE_NAME&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;옵션에 추가된 --no-data 가 dump를 뜨면서 table 내의 데이터를 무시하도록 하는 역할한다.&lt;/p&gt;</description>
      <category>DB</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/47</guid>
      <comments>https://stackov.tistory.com/47#entry47comment</comments>
      <pubDate>Fri, 21 Jun 2019 11:16:49 +0900</pubDate>
    </item>
    <item>
      <title>[QT] C++ std::string과 QString 간의 문자열 형 변환 방법</title>
      <link>https://stackov.tistory.com/46</link>
      <description>&lt;h1&gt;개요&lt;/h1&gt;
&lt;p&gt;QT C++로 프로그램을 작성하면, 타 라이브러리와의 연동을 위해 &lt;code&gt;std::string&lt;/code&gt; 을 &lt;code&gt;QString&lt;/code&gt;으로 변환하거나, 그 반대를 수행해야 하는 경우가 잦다.&lt;/p&gt;
&lt;p&gt;이를 해결하기 위한 방법은 다음과 같다.&lt;/p&gt;
&lt;h1&gt;std::string -&amp;gt; QString&lt;/h1&gt;
&lt;h2&gt;QString의 함수 이용&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;QString&lt;/code&gt;은 &lt;code&gt;std::string&lt;/code&gt;을 &lt;code&gt;QString&lt;/code&gt;으로 변환해주는 함수 &lt;code&gt;QString::fromStdString&lt;/code&gt; 함수를 제공한다&lt;/p&gt;
&lt;p&gt;사용 예시&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-C++&quot;&gt;std::string str =&amp;quot;Hello, World!&amp;quot;;
QString qstr = QString::fromStdString(str);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 방법을 사용하면 손쉽게 형 변환이 가능하다.&lt;/p&gt;
&lt;h2&gt;string pointer 이용&lt;/h2&gt;
&lt;p&gt;std::string을 QString으로 변경하기 위한, char 배열로 변경한 결과를 QString의 생성자에 넣어주면 된다.&lt;/p&gt;
&lt;p&gt;이는 아래의 예제 코드처럼 작성하면 QString으로 형변환된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-C++&quot;&gt;std::string str = &amp;quot;Hello, World!&amp;quot;;
QString qstr = QString(str.c_str());&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;QString -&amp;gt; std::string&lt;/h1&gt;
&lt;p&gt;QT 프로그램에서 타 라이브러리의 함수를 호출하기 위해선, &lt;code&gt;QString&lt;/code&gt; 변수를 &lt;code&gt;std::string&lt;/code&gt;으로 변환해야 하는 경우도 발생한다.&lt;/p&gt;
&lt;p&gt;이 역시도 &lt;code&gt;QString&lt;/code&gt; 에서 &lt;code&gt;QString&lt;/code&gt;을 &lt;code&gt;std::string&lt;/code&gt;으로 변환해주는 함수 &lt;code&gt;QString::toStdString&lt;/code&gt;을 제공한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-C++&quot;&gt;QString qstr = &amp;quot;Hello, World!&amp;quot;;
std::string str = qstr.toStdString();&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;결론&lt;/h1&gt;
&lt;p&gt;QT에서 제공하는 &lt;code&gt;QString&lt;/code&gt; 클래스는 기존의 C++ 객체와의 호환을 위한 다양한 기능을 제공하며, 이를 통해 효율적인 코딩이 가능하다.&lt;/p&gt;
&lt;p&gt;위에 언급한 것 이외에도 &lt;code&gt;QString&lt;/code&gt;의 &lt;code&gt;QString QString::fromLocal8Bit(QByteArray*)&lt;/code&gt;나 &lt;code&gt;QByteArray QString::toLocal8Bit()&lt;/code&gt; 같은 함수를 통해 &lt;code&gt;QByteArray&lt;/code&gt; 또는 &lt;code&gt;char*&lt;/code&gt;에서 &lt;code&gt;QString&lt;/code&gt;로 혹은 그 반대로 변환할 수 있는 기능을 제공한다.&lt;/p&gt;</description>
      <category>Programming/QT</category>
      <category>C++</category>
      <category>QString</category>
      <category>QT</category>
      <category>std::string</category>
      <category>형변환</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/46</guid>
      <comments>https://stackov.tistory.com/46#entry46comment</comments>
      <pubDate>Tue, 18 Jun 2019 13:34:34 +0900</pubDate>
    </item>
    <item>
      <title>[C++] different underlying type in enum 'enum class TypeName'</title>
      <link>https://stackov.tistory.com/45</link>
      <description>&lt;h2&gt;Error 발생 원인&lt;/h2&gt;
&lt;p&gt;enum class를 선언하고, 공통 헤더에서 prototype만 정의하려는 시도를 진행하였으나, 제목과 같은 에러가 발생하였다.&lt;br /&gt;이러한 현상은 enum class의 구현부의 underlying type과 prototype의 underlying type이 서로 달라 발생하는 오류이다.&lt;/p&gt;
&lt;h3&gt;예제 코드&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;global.h&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum class Type;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;enumclass.h&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;
#include &quot;global.h&quot;
enum class Type : unsigned int {
    A,
    B,
    C
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 global.h에는 별다른 type을 지정안했으나, enumclass.h에는 별도의 타입이 지정되어 있을 때 발생한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;해결 방법&lt;/h2&gt;
&lt;p&gt;이러한 부분은 아래와 같이 타입을 지정해주면 해결 된다.&lt;/p&gt;
&lt;h3&gt;예제 코드&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;global.h&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum class Type : unsigned int;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;enumclass.h&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;#include &quot;global.h&quot;
enum class Type : unsigned int {
    A,
    B,
    C
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Programming/C &amp;amp;  C++</category>
      <category>C++</category>
      <category>enum</category>
      <category>enum class</category>
      <category>error</category>
      <category>type</category>
      <category>underlying type</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/45</guid>
      <comments>https://stackov.tistory.com/45#entry45comment</comments>
      <pubDate>Fri, 14 Jun 2019 10:00:53 +0900</pubDate>
    </item>
    <item>
      <title>[C++] Inheritance: 'A' is an inaccessible base of 'B'</title>
      <link>https://stackov.tistory.com/44</link>
      <description>&lt;p&gt;C++에서 접근제어 지정자를 잘못 지정해서 발생하는 현상이다.&lt;/p&gt;
&lt;p&gt;아래와 같이 업캐스팅으로 부모 클래스의 자료형으로 자식 클래스의 포인터를 가리키려 할 때, 이와 같은 현상이 발생한다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;class A {
}
class B : A {
}

A* obj = new B();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이와 같은 문제는, 접근제어 지정자를 변경함으로서 해결 가능하다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;class A {
}
class B : public A {
}

A* obj = new B();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/C &amp;amp;  C++</category>
      <category>C++</category>
      <category>동적할당</category>
      <category>상속</category>
      <category>업캐스트</category>
      <category>접근제어</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/44</guid>
      <comments>https://stackov.tistory.com/44#entry44comment</comments>
      <pubDate>Wed, 12 Jun 2019 18:31:37 +0900</pubDate>
    </item>
    <item>
      <title>[QT] QObject::connect: Cannot queue arguments of type 'Type Name'</title>
      <link>https://stackov.tistory.com/43</link>
      <description>&lt;p&gt;QT 개발을 하던 도중, 특정 클래스를 인자로 사용하는 signal/slot을 생성하고, Connect를 할 경우&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;QObject::connect: Cannot queue arguments of type &amp;#39;Type Name&amp;#39;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;메시지가 출력될 때가 있다.&lt;/p&gt;
&lt;p&gt;이러한 부분은, QT에 해당 class의 meta type이 추가되지 않아 발생하는 현상으로, 아래와 같은 코드를 추가하여 해결할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c++&quot;&gt;qRegisterMetaType&amp;lt;CMultiTrackMini&amp;gt;(&amp;quot;CMultiTrackMini&amp;quot;);&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Programming/QT</category>
      <category>C</category>
      <category>C++</category>
      <category>qRegisterMetaType</category>
      <category>QT</category>
      <category>개발</category>
      <category>코딩</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/43</guid>
      <comments>https://stackov.tistory.com/43#entry43comment</comments>
      <pubDate>Wed, 12 Jun 2019 13:20:59 +0900</pubDate>
    </item>
    <item>
      <title>[SVN] 원격 Repository에 파일(directory) 추가 / 제거하기</title>
      <link>https://stackov.tistory.com/42</link>
      <description>&lt;p&gt;SVN을 사용하다 보면, 원격 Repository에 파일을 업로드/삭제를 해야할 일이 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. 원격 Repository에 파일(directory) 업로드&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1559611026949&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;svn import LOCAL_PATH REMOTE_PATH&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;주의할점으로, directory를 업로드할 때, LOCAL_PATH로 Directory를, REMOTE_PATH로 업로드할 위치(parent directory)를 입력하면 parent directory에 파일만 업로드 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;local에 아래의 구조를 가진 a directory를 &lt;a href=&quot;http://svn.url&quot;&gt;http://svn.url&lt;/a&gt;/A에 업로드 할 때&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;box&quot;&gt;[폴더 구조]&lt;br /&gt;a&lt;br /&gt;a/b.txt&lt;br /&gt;a/c.txt&lt;/blockquote&gt;
&lt;pre id=&quot;code_1559611387437&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;svn import ./a http://svn.url/A&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같은 커맨드 명령어를 입력하게 될 것이며, 이에 대한 결과로 아래와 처럼 될 것이라 생각할 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;box&quot;&gt;[SVN Repository]&lt;br /&gt;&lt;span style=&quot;color: #96d5fa;&quot;&gt;A/1&lt;/span&gt; &lt;span style=&quot;color: #96d5fa;&quot;&gt;(기존파일)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ff9a85;&quot;&gt;A/a&amp;nbsp;(추가)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ff9a85;&quot;&gt;A/a/b.txt&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ff9a85;&quot;&gt;A/a/c.txt&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;하지만&amp;nbsp; 결과는 아래처럼 나타난다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;box&quot;&gt;[SVN Repository]&lt;br /&gt;&lt;span style=&quot;color: #96d5fa;&quot;&gt;A/1 (기존파일)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ff9a85;&quot;&gt;A/b.txt&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ff9a85;&quot;&gt;A/c.txt&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;이를 해결하기 위해선, 아래와 같이 추가 생성될 directory까지 추가하여 커맨드를 입력한다.&lt;/p&gt;
&lt;pre id=&quot;code_1559611517122&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;svn import ./a http://svn.url/A/a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그러면 원하던 결과를 얻을 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. 원격 Repository에 파일(directory) 삭제&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1559611598413&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;svn rm REMOTE_PATH&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;파일 삭제는 단순히 Repository에서 지울 대상이 존재하는 URL만 입력하면 손쉽게 제거 가능하다.&lt;/p&gt;
&lt;p&gt;방금 추가한 a directory를 지우기 위해선,&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1559611685902&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;svn rm http://svn.url/A/a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 작성만 하면 손쉽게 삭제 가능하다.&lt;/p&gt;</description>
      <category>Code/svn</category>
      <category>delete</category>
      <category>import</category>
      <category>SVN</category>
      <category>버전관리</category>
      <category>파일삭제</category>
      <category>파일추가</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/42</guid>
      <comments>https://stackov.tistory.com/42#entry42comment</comments>
      <pubDate>Tue, 4 Jun 2019 10:28:48 +0900</pubDate>
    </item>
    <item>
      <title>[CentOS] Gnome 환경에서, Titlebar 크기 조절하기</title>
      <link>https://stackov.tistory.com/41</link>
      <description>&lt;p&gt;gnome3 환경에서, Titlebar는 GTK-3설정에 영향을 받는다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;경로에&amp;nbsp;&lt;span style=&quot;background-color: #808080; color: #ffffff;&quot;&gt;~/.config/gtk-3.0/gtk.css&lt;/span&gt;에 아래와 같은 내용을 입력하면 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1558923459349&quot; class=&quot;html xml&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* shrink headerbars (don't forget semicolons after each property) */
headerbar {
    min-height: 0px;
    padding-left: 2px; /* same as childrens vertical margins for nicer proportions */
    padding-right: 2px;
    background-color: #2d2d2d;
}

headerbar entry,
headerbar spinbutton,
headerbar button,
headerbar separator {
    margin-top: 0px; /* same as headerbar side padding for nicer proportions */
    margin-bottom: 0px;
}

/* shrink ssd titlebars */
.default-decoration {
    min-height: 0; /* let the entry and button drive the titlebar size */
    padding: 0px;
    background-color: #2d2d2d;
}

.default-decoration .titlebutton {
    min-height: 0px; /* tweak these two props to reduce button size */
    min-width: 0px;
}

window.ssd headerbar.titlebar {
    padding-top: 3px;
    padding-bottom: 3px;
    min-height: 0;
}

window.ssd headerbar.titlebar button.titlebutton {
    padding-top: 3px;
    padding-bottom:3px;
    min-height: 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OS/Linux</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/41</guid>
      <comments>https://stackov.tistory.com/41#entry41comment</comments>
      <pubDate>Mon, 27 May 2019 11:17:46 +0900</pubDate>
    </item>
    <item>
      <title>[vscode] VSCode 에서 React Live debug 설정하기</title>
      <link>https://stackov.tistory.com/40</link>
      <description>&lt;p&gt;VSCode에서 React 코드를 작성할 때, 코드가 변경됨을 실시간으로 크롬으로 확인할 수 있는 방법이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. Debugger for chrome extension 설치&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;좌측의 extension 버튼 클릭 후, chrome을 검색하여 debugger for chrome 을 설치한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷, 2019-05-23 17-45-37.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xRgaA/btqvv3Okedq/LomU1CrfT8EYmXhkHXuvbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xRgaA/btqvv3Okedq/LomU1CrfT8EYmXhkHXuvbk/img.png&quot; data-alt=&quot;vscode extension&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xRgaA/btqvv3Okedq/LomU1CrfT8EYmXhkHXuvbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxRgaA%2Fbtqvv3Okedq%2FLomU1CrfT8EYmXhkHXuvbk%2Fimg.png&quot; data-filename=&quot;스크린샷, 2019-05-23 17-45-37.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;vscode extension&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. launch.json 파일을 생성한다&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;.vscode 디렉토리에,&amp;nbsp; 아래와 같은 내용을 가진 launch.json 파일을 생성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1558601266230&quot; class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;version&quot;: &quot;0.2.0&quot;,
    &quot;configurations&quot;: [
        
        {
            &quot;name&quot;: &quot;Chrome&quot;,
            &quot;type&quot;: &quot;chrome&quot;,
            &quot;request&quot;: &quot;launch&quot;,
            &quot;url&quot;: &quot;http://localhost:3000&quot;,
            &quot;webRoot&quot;: &quot;${workspaceRoot}/src&quot;
        }
    ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. Terminal에서 react application을 실행한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4v3Bs/btqvxXzbMlx/b4s78RoDNV3CIhGIRSYBC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4v3Bs/btqvxXzbMlx/b4s78RoDNV3CIhGIRSYBC0/img.png&quot; data-alt=&quot;npm start를 통해 react 실행&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4v3Bs/btqvxXzbMlx/b4s78RoDNV3CIhGIRSYBC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4v3Bs%2FbtqvxXzbMlx%2Fb4s78RoDNV3CIhGIRSYBC0%2Fimg.png&quot; data-filename=&quot;blob&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;npm start를 통해 react 실행&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. F5를 눌러 디버깅을 시작한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;위의 설정이 완료될 경우, 자동으로 chrome 창이 켜지게 되며, src 디렉터리 내부의 코드를 수정하면 자동으로 refresh 된다.&lt;/p&gt;</description>
      <category>Tools/vscode</category>
      <category>JS</category>
      <category>node</category>
      <category>react</category>
      <category>VSCode</category>
      <category>Web</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/40</guid>
      <comments>https://stackov.tistory.com/40#entry40comment</comments>
      <pubDate>Thu, 23 May 2019 17:51:46 +0900</pubDate>
    </item>
    <item>
      <title>MarkDown Test</title>
      <link>https://stackov.tistory.com/39</link>
      <description>&lt;h1&gt;markdown Test&lt;/h1&gt;
&lt;h2&gt;test2&lt;/h2&gt;
&lt;h1&gt;code block&lt;/h1&gt;
&lt;pre&gt;&lt;code class=&quot;language-c++&quot;&gt;void main() {
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import hi
function a() {
  console.log(&amp;#39;hello world!&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Tag Test&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;aa&lt;/strong&gt; hi&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;구분선 테스트&lt;/h2&gt;
&lt;h2&gt;Link Test&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://naver.com&quot;&gt;LinkTest&lt;/a&gt;&lt;/p&gt;</description>
      <category>잡다</category>
      <author>후유증</author>
      <guid isPermaLink="true">https://stackov.tistory.com/39</guid>
      <comments>https://stackov.tistory.com/39#entry39comment</comments>
      <pubDate>Sat, 18 May 2019 11:09:20 +0900</pubDate>
    </item>
  </channel>
</rss>