2010年4月21日 星期三

Build Failed with Link Error (開發iPhone過程中遇到Link error 的解決方法)

由於專案需要,從農曆年後開始接觸 iPhone程式的開發
開發過程中正巧遇到一個很奇怪的 bug 一直編不成功
試著從紅色驚嘆號來追看看兇手到底藏在哪邊

結果xcode的debug只告訴我
Link /Users/administrator/...
 ".objc_class_name_NSManageObject", referenced from:
.objc_class_name_Camera in Camera.o
ld: symbol(s) not found

上google查了的結果真的少的可憐...
不過很明顯是Link出了問題

後來搞清楚是某個.m檔 有import <CoreData/CoreData.h>
但是整個專案的Frameworks裡面沒有加進去啦

解決方法:

step1.


step2. (我就是少了CoreData這一味啦)

2010年4月15日 星期四

How to update file's version automatically in MFC (如何在MFC專案中自動更新版號)

最近工作上被argue在軟體的版本編號方式要長得像這樣:
X.YY (build ZZ)
而我原本在wiki上面參考來的編法是這樣的:
a.b.yy.mmdd
不過customer永遠是對的,那就來改一下吧
只是這樣一來,我的程式資訊需要紀錄我build的情況
光有svn再到project 的rc檔裡面慢慢改實在很沒效率

幸好網路上有找到相關資源,而且一試就成功 (it works like a charm!)
我這邊簡單中文筆記一下~
1. 首先找到專案資料夾下的 "ProjectName.rc",用文字編輯器打開

2. 接著在同樣的路徑下應該還會有個 res檔案夾 打開裡面有個 "ProjectName.rc2" ,
同樣也是用文字編輯器打開

3. 把"ProjectName.rc"裡頭的這個部份通通剪下來
//////////////////////////////////
//
//Version
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGMASK 0x3fl
#ifdef _DEBUG
...
...
BEGIN
VALUE "Translation", 0x409, 1200
END
END

然後貼到"ProjectName.rc2" "Add manually edited resources here..."註解之後
不過"ProjectName.rc2"在編輯完,記得在最後一行按個Enter(回車鍵)讓他換個行
不然編譯時就會出現 fatal error RC1004: unexpected end or file found 的錯誤訊息
害我走了好多冤枉路阿...

4. 回頭在"ProjectName.rc"裡面 找到
#ifdef APSTUDIO_INVOKED
#include "targetver.h"
#endif
#include "afxres.h"
#include "res\ProjectName.rc2" //<-- add this line
然後將rc與rc2兩個檔案儲存

5. 快完成了~接下來在專案的header files資料夾下新增一個VersionNo.h的檔頭
#define FILEVER 1,0,0,1
#define PRODUCTVER 1,0,0,1
#define STRFILEVER "1, 0, 0, 1\\0"
#define STRPRODUCTVER "1, 0, 0, 1\\0"
兩個反斜線是為了我要抓後面的build number,網路上參考資料只有一條

6. 然後我們需要新增一個marco (tool->Marcos->New Marco Project)
Module1的project名稱可以一自己喜好更換,建立好雙擊那個module會開啟一個Marco 的IDE

7. 過來就是複製貼上囉~
Imports EnvDTE
Imports System.Diagnostics

Public Module BuildDone '<--------------- Your module name




Function GetProjectDir(ByVal FullName)

Dim proj_path

proj_path = Split(StrReverse(FullName), "\", -1, 1)



Dim count

count = UBound(proj_path)



Dim full_path

full_path = ""

Dim i



For i = 1 To count

full_path = full_path & "\" & proj_path(i)

Next



GetProjectDir = StrReverse(full_path)



End Function



Sub ReplaceText(ByVal objSel As TextSelection, _

ByVal count As Integer, ByVal incrementby As Integer, _

ByVal Type As Integer)



'selection represents the TextSelection object

'count represents the position of the version number

'to be incremented

'incrementally represents a number that will be added

'to the existing version number



Dim strTemp As String

Dim i



strTemp = ""

objSel.EndOfLine()



If Type = 0 Then

For i = 1 To count

If strTemp.StartsWith(",") = True Then

Exit For

Else

objSel.CharLeft(True, 1)

strTemp = objSel.Text

End If

Next

strTemp = strTemp.Remove(0, 1)

strTemp = strTemp + incrementby

objSel.Text = "," & strTemp

Else

For i = 1 To count

If strTemp.StartsWith("\") = True Then

Exit For

Else

objSel.CharLeft(True, 1)

strTemp = objSel.Text

End If

Next

strTemp = strTemp.Remove(0, 1)

strTemp = strTemp.Remove(strTemp.Length - 1, 1)

strTemp = strTemp + incrementby

objSel.Text = "\" & strTemp & """"

End If



End Sub



Dim WithEvents bldevents As BuildEvents

Dim applicationObject As EnvDTE.DTE



Sub BuildDoneEvents()

Dim addInInstance As EnvDTE.AddIn



applicationObject = CType(Application, EnvDTE.DTE)

bldevents = CType(applicationObject.Events. _

BuildEvents, EnvDTE.BuildEvents)

End Sub



Private Sub bldevents_OnBuildDone(ByVal _

Scope As EnvDTE.vsBuildScope, _

ByVal Action As EnvDTE. _

vsBuildAction) Handles _

bldevents.OnBuildDone

'This event will be triggered after every build

'of a project



'Obtain the full path of the active project

Dim full_path

full_path = GetProjectDir(DTE.ActiveDocument.Path)



full_path = full_path & "VersionNo.h" '<----------Your header name



'Open the VersionNo.h file

Dim doc As Document

DTE.ItemOperations.OpenFile(full_path)



Dim objDoc As TextDocument

'Obtain the TextSelection object

objDoc = DTE.ActiveDocument.Object("TextDocument")



Dim objSel As TextSelection = _

DTE.ActiveDocument.Selection



objSel.StartOfDocument()



'Increment the version information

ReplaceText(objSel, 5, 1, 0)

objSel.LineDown()

objSel.StartOfLine()

ReplaceText(objSel, 5, 1, 0)

objSel.LineDown()

objSel.StartOfLine()

ReplaceText(objSel, 5, 1, 100)

objSel.LineDown()

objSel.StartOfLine()

ReplaceText(objSel, 5, 1, 100)



ActiveDocument.Save()

ActiveDocument.Close()

End Sub





End Module



8. save之後回到原本VC介面 在Marco Explorer裡面對我們的module右鍵按下選擇run check 一下VersionNo.h ,成功的話會發現數字隨著build次數增加 嗯~至於如何在程式當中取得version 可以使用VS_FIXEDFILEINFO ,VerQueryValue ,GetFileVersionInfoSize ,GetFileVersionInfo 幾個配合,並透過 HIWORD(fixed_file_info->dwFileVersionMS)
LOWORD(fixed_file_info->dwFileVersionMS)
HIWORD(fixed_file_info->dwFileVersionLS)
LOWORD(fixed_file_info->dwFileVersionLS)
來取得version number ,還有很多詳細的作法網路上很好找到

AfxExtractSubString 可以取得特定位置的字串
ex: AfxExtractSubString(str, FullString, 1, '\\');
這邊的例子是將字串以 "\" (反斜線)切割, 取位置1的字串
也就是說, 如果我的FullString=1, 0, 0, 1\7 ,那我就會取到 7


內容回應